IRkernel/0000755000176200001440000000000013572476532012003 5ustar liggesusersIRkernel/NAMESPACE0000644000176200001440000000254513572471527013227 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(comm_manager) export(installspec) export(jupyter_option_defaults) export(log_debug) export(log_error) export(log_info) export(main) exportClasses(Comm) exportClasses(CommManager) import(digest) import(methods) import(uuid) importFrom(IRdisplay,prepare_mimebundle) importFrom(IRdisplay,publish_mimebundle) importFrom(crayon,blue) importFrom(crayon,green) importFrom(crayon,red) importFrom(evaluate,evaluate) importFrom(evaluate,flush_console) importFrom(evaluate,new_output_handler) importFrom(evaluate,parse_all) importFrom(grDevices,pdf) importFrom(grDevices,png) importFrom(jsonlite,fromJSON) importFrom(jsonlite,toJSON) importFrom(pbdZMQ,ZMQ.MC) importFrom(pbdZMQ,zmq.bind) importFrom(pbdZMQ,zmq.ctx.new) importFrom(pbdZMQ,zmq.getsockopt) importFrom(pbdZMQ,zmq.msg.recv) importFrom(pbdZMQ,zmq.msg.send) importFrom(pbdZMQ,zmq.poll) importFrom(pbdZMQ,zmq.poll.get.revents) importFrom(pbdZMQ,zmq.recv) importFrom(pbdZMQ,zmq.recv.multipart) importFrom(pbdZMQ,zmq.send) importFrom(pbdZMQ,zmq.send.multipart) importFrom(pbdZMQ,zmq.setsockopt) importFrom(pbdZMQ,zmq.socket) importFrom(repr,mime2repr) importFrom(repr,repr_option_defaults) importFrom(stats,setNames) importFrom(utils,capture.output) importFrom(utils,getFromNamespace) importFrom(utils,getS3method) importFrom(utils,head) importFrom(utils,str) importFrom(utils,tail) IRkernel/LICENSE0000644000176200001440000000011113142351436012765 0ustar liggesusersYEAR: 2014 COPYRIGHT HOLDER: Thomas Kluyver, Philipp Angerer, Jan Schulz IRkernel/README.md0000644000176200001440000000620713400224421013241 0ustar liggesusers# Native R kernel for Jupyter [![b-Travis]][Travis] [![b-CRAN]][CRAN] [b-Travis]: https://travis-ci.org/IRkernel/IRkernel.svg?branch=master "Build status" [Travis]: https://travis-ci.org/IRkernel/IRkernel [b-CRAN]: https://www.r-pkg.org/badges/version/IRkernel "Comprehensive R Archive Network" [CRAN]: https://cran.r-project.org/package=IRkernel For detailed requirements and install instructions see [irkernel.github.io](http://irkernel.github.io/) ## Requirements * [Jupyter](http://jupyter.org). * A current [R installation](https://www.R-project.org). ## Installation This package is available on CRAN: ```R install.packages('IRkernel') IRkernel::installspec() # to register the kernel in the current R installation ``` Per default `IRkernel::installspec()` will install a kernel with the name “ir” and a display name of “R”. Multiple calls will overwrite the kernel with a kernel spec pointing to the last R interpreter you called that commands from. You can install kernels for multiple versions of R by supplying a `name` and `displayname` argument to the `installspec()` call (You still need to install these packages in all interpreters you want to run as a jupyter kernel!): ```r # in R 3.3 IRkernel::installspec(name = 'ir33', displayname = 'R 3.3') # in R 3.2 IRkernel::installspec(name = 'ir32', displayname = 'R 3.2') ``` Now both R versions are available as an R kernel in the notebook. ### If you encounter problems during installation 1. Have a look at the [full installation instructions](http://irkernel.github.io/installation/)! 2. [Search the existing open and closed issues](https://github.com/IRkernel/IRkernel/issues?utf8=%E2%9C%93&q=is%3Aissue). 3. If you are sure that this is a new problem, [file an issue](https://github.com/IRkernel/IRkernel/issues/new). ## Running the notebook If you have Jupyter installed, you can create a notebook using IRkernel from the dropdown menu. You can also start other interfaces with an R kernel: ```bash # “ir” is the kernel name installed by the above `IRkernel::installspec()` # change if you used a different name! jupyter qtconsole --kernel=ir jupyter console --kernel=ir ``` ## Run a stable release in a Docker container Refer to the [jupyter/docker-stacks r-notebook](https://github.com/jupyter/docker-stacks/tree/master/r-notebook) repository If you have a Docker daemon running, e.g. reachable on localhost, start a container with: ```bash docker run -d -p 8888:8888 jupyter/r-notebook ``` Open localhost:8888 in your browser. All notebooks from your session will be saved in the current directory. On other platforms without docker, this can be started using `docker-machine` by replacing “localhost” with an IP from `docker-machine ip `. With the deprecated `boot2docker`, this IP will be `boot2docker ip`. ## Develop and run from source in a Docker container ```bash make docker_dev_image #builds dev image and installs IRkernel dependencies from github make docker_dev #mounts source, installs, and runs Jupyter notebook; docker_dev_image is a prerequisite make docker_test #builds the package from source then runs the tests via R CMD check; docker_dev_image is a prerequisite ``` IRkernel/man/0000755000176200001440000000000013572471421012546 5ustar liggesusersIRkernel/man/log.Rd0000644000176200001440000000110113524511623013603 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logging.r \name{log} \alias{log} \alias{log_debug} \alias{log_info} \alias{log_error} \title{Kernel logging functions} \usage{ log_debug(...) log_info(...) log_error(...) } \arguments{ \item{...}{message to log} } \description{ A set of exported logging utilities that have the capability to be used in upstream projects. Log level and log file can be set via R package options e.g. \code{options(jupyter.log_level = 2L)} or from the environment variables JUPYTER_LOG_LEVEL and JUPYTER_LOGFILE. } IRkernel/man/installspec.Rd0000644000176200001440000000231513572471447015367 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/installspec.r \name{installspec} \alias{installspec} \title{Install the kernelspec to tell Jupyter about IRkernel.} \usage{ installspec( user = NULL, name = "ir", displayname = "R", rprofile = NULL, prefix = NULL ) } \arguments{ \item{user}{Install into user directory (\href{https://specifications.freedesktop.org/basedir-spec/latest/ar01s03.html}{\code{$XDG_DATA_HOME}}\code{/jupyter/kernels}) or globally? (default: NULL but treated as TRUE if "prefix" is not specified)} \item{name}{The name of the kernel (default "ir")} \item{displayname}{The name which is displayed in the notebook (default: "R")} \item{rprofile}{(optional) Path to kernel-specific Rprofile (defaults to system-level settings)} \item{prefix}{(optional) Path to alternate directory to install kernelspec into (default: NULL)} } \value{ Exit code of the \code{jupyter kernelspec install} call. } \description{ This can be called multiple times for different R interpreter, but you have to give a different name (and displayname to see a difference in the notebook UI). If the same name is give, it will overwrite older versions of the kernel spec with that name! } IRkernel/man/IRkernel-package.Rd0000644000176200001440000000356213524511623016143 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/options.r, R/help.r \docType{data} \name{jupyter_option_defaults} \alias{jupyter_option_defaults} \alias{IRkernel-package} \alias{IRkernel} \alias{IRkernel-options} \title{An R kernel for Jupyter.} \format{An object of class \code{list} of length 7.} \usage{ jupyter_option_defaults } \description{ Jupyter speaks a JSON+ZMQ protocol to a 'kernel' which is responsible for executing code. This package is a kernel for the R language. } \section{Options}{ The following can be set/read via \code{options(opt.name = ...)} / \code{getOption('opt.name')} \describe{ \item{\code{jupyter.log_level}}{1L (errors), 2L (warnings), or 3L (debug). 1L is the default.} \item{\code{jupyter.pager_classes}}{Classes to use the pager for instead of displaying them inline. Default: help pages} \item{\code{jupyter.in_kernel}}{\code{TRUE} if this code is executed in a running kernel. Set to pretend being/not being in a kernel} \item{\code{jupyter.rich_display}}{Use more than just text display} \item{\code{jupyter.display_mimetypes}}{ The formats emitted when any return value is to be displayed (default: all mimetypes listed \href{http://ipython.org/ipython-doc/stable/api/generated/IPython.core.formatters.html#IPython.core.formatters.format_display_data}{here}) } \item{\code{jupyter.plot_mimetypes}}{ The plot formats emitted to the frontend when a plot is displayed. (default: image/png and application/pdf) } \item{\code{jupyter.plot_scale}}{ The ratio (notebook PPI / \code{repr.plot.res}). E.g.: With the defaults \code{repr.plot.res}=120 px/in (PPI) and \code{jupyter.plot_scale}=2, a 1in\eqn{\times}1in image will be displayed as a 0.5in\eqn{\times}0.5in, 240 PPI image. (default: 2, fit for retina displays) } } } \seealso{ \link{installspec} } \keyword{datasets} IRkernel/man/CommManager-class.Rd0000644000176200001440000000044213142351436016322 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/comm_manager.r \docType{class} \name{CommManager-class} \alias{CommManager-class} \alias{CommManager} \title{The CommManager} \description{ Has methods able to register comms/targets and process comm messages } IRkernel/man/main.Rd0000644000176200001440000000051613142351436013757 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/main.r \name{main} \alias{main} \title{Initialise and run the kernel} \usage{ main(connection_file = "") } \arguments{ \item{connection_file}{The path to the Jupyter connection file, written by the frontend} } \description{ Initialise and run the kernel } IRkernel/man/Comm-class.Rd0000644000176200001440000000037313142351436015032 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/comm_manager.r \docType{class} \name{Comm-class} \alias{Comm-class} \alias{Comm} \title{The Comm} \description{ Has methods able to register and handle message callbacks } IRkernel/man/comm_manager.Rd0000644000176200001440000000050613142351436015457 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/environment_runtime.r \name{comm_manager} \alias{comm_manager} \title{Get global CommManager instance} \usage{ comm_manager() } \value{ \link{CommManager} instance if a kernel is running, else NULL } \description{ Get global CommManager instance } IRkernel/DESCRIPTION0000644000176200001440000000330413572476532013511 0ustar liggesusersPackage: IRkernel Title: Native R Kernel for the 'Jupyter Notebook' Description: The R kernel for the 'Jupyter' environment executes R code which the front-end ('Jupyter Notebook' or other front-ends) submits to the kernel via the network. Version: 1.1 Authors@R: c( person('Thomas', 'Kluyver', role = c('aut', 'cph'), email = 'thomas@kluyver.me.uk'), person('Philipp', 'Angerer', role = c('aut', 'cph', 'cre'), email = 'phil.angerer@gmail.com', comment = c(ORCID = "0000-0002-0369-2888")), person('Jan', 'Schulz', role = c('aut', 'cph'), email = 'jasc@gmx.net'), person('Karthik', 'Ram', role = c('aut', 'cph'), email = 'karthik.ram@gmail.com')) URL: https://irkernel.github.io BugReports: https://github.com/IRkernel/IRkernel/issues/ Depends: R (>= 3.2.0) Suggests: testthat, roxygen2 SystemRequirements: jupyter, jupyter_kernel_test (Python package for testing) License: MIT + file LICENSE LazyData: true Encoding: UTF-8 Imports: repr (>= 0.4.99), methods, evaluate (>= 0.10), IRdisplay (>= 0.3.0.9999), pbdZMQ (>= 0.2-1), crayon, jsonlite (>= 0.9.6), uuid, digest Collate: 'class_unions.r' 'logging.r' 'comm_manager.r' 'compat.r' 'completion.r' 'environment_runtime.r' 'environment_shadow.r' 'options.r' 'execution.r' 'handlers.r' 'help.r' 'installspec.r' 'utils.r' 'kernel.r' 'main.r' 'onload.r' RoxygenNote: 7.0.0 NeedsCompilation: no Packaged: 2019-12-06 15:27:20 UTC; phil Author: Thomas Kluyver [aut, cph], Philipp Angerer [aut, cph, cre] (), Jan Schulz [aut, cph], Karthik Ram [aut, cph] Maintainer: Philipp Angerer Repository: CRAN Date/Publication: 2019-12-06 16:10:02 UTC IRkernel/tests/0000755000176200001440000000000013142351436013131 5ustar liggesusersIRkernel/tests/testthat/0000755000176200001440000000000013572476532015005 5ustar liggesusersIRkernel/tests/testthat/test-options.r0000644000176200001440000000105313142351436017623 0ustar liggesuserscontext('default options') test_that('default options are set', { expect_true(getOption('jupyter.rich_display')) expect_equal(getOption('jupyter.log_level'), 1L) expect_equal(getOption('jupyter.logfile'), NA) expect_equal(getOption('jupyter.pager_classes'), c( 'packageIQR', 'help_files_with_topic')) expect_equal(getOption('jupyter.plot_mimetypes'), c( 'text/plain', 'image/png')) # this is not a kernel itself, only the loaded package! expect_equal(getOption('jupyter.in_kernel'), FALSE) }) IRkernel/tests/testthat/njr/0000755000176200001440000000000013572471530015567 5ustar liggesusersIRkernel/tests/testthat/njr/ndjson_testrunner.py0000644000176200001440000000632413442700337021726 0ustar liggesusersimport sys import io import json import unittest import warnings from collections import OrderedDict from typing import Optional, Dict, Any from contextlib import contextmanager __all__ = ['JSONTestResult', 'JSONTestRunner'] class JSONTestResult(unittest.TestResult): def __init__(self, stream, failfast, buffer, tb_locals): super().__init__(stream) self.stream = stream self.failfast = failfast self.buffer = buffer self.tb_locals = tb_locals def test_run(self, test): self.startTestRun() try: test(self) finally: self.stopTestRun() def result_to_dict(self, type_: str, test: unittest.TestCase, err: Optional[Any]=None) -> Dict[str, Optional[str]]: msg = None if isinstance(err, tuple) and len(err) == 3: msg = self._exc_info_to_string(err, test) elif err: msg = str(err) return OrderedDict([ ('type', type_), ('id', test.id()), ('desc', test.shortDescription()), # May be None ('msg', msg), ]) def write_result(self, typ_: str, test: unittest.TestCase, err: Optional[Any]=None): json.dump(self.result_to_dict(typ_, test, err), self.stream, separators=(',', ':')) self.stream.write('\n') def addSuccess(self, test): super().addSuccess(test) self.write_result('success', test) def addExpectedFailure(self, test, err): super().addExpectedFailure(test, err) self.write_result('expected_failure', test, err) def addFailure(self, test, err): super().addFailure(test, err) self.write_result('failure', test, err) def addError(self, test, err): super().addError(test, err) self.write_result('error', test, err) def addUnexpectedSuccess(self, test): super().addUnexpectedSuccess(test) self.write_result('unexpected_success', test) def addSkip(self, test, reason): super().addSkip(test, reason) self.write_result('skip', test, reason) def addSubTest(self, test, subtest, err): super().addSubTest(test, subtest, err) if err is None: self.write_result('success', subtest) elif issubclass(err[0], test.failureException): self.write_result('failure', subtest, err) else: self.write_result('error', subtest, err) class JSONTestRunner: """TODO""" def __init__( self, stream: io.TextIOBase=None, failfast: bool=False, buffer: bool=False, warnings: Optional[str]=None, *, tb_locals: bool=False ): """Construct a JSONTestRunner.""" self.stream = sys.stdout if stream is None else stream self.failfast = failfast self.buffer = buffer self.tb_locals = tb_locals self.warnings = warnings @contextmanager def filter_warnings(self): """Install own warnings filter for the context""" with warnings.catch_warnings(): if self.warnings: warnings.simplefilter(self.warnings) if self.warnings in ['default', 'always']: warnings.filterwarnings('module', category=DeprecationWarning, message=r'Please use assert\w+ instead.') yield def run(self, test): """Run the given test case or test suite.""" result = JSONTestResult(self.stream, self.failfast, self.buffer, self.tb_locals) unittest.registerResult(result) with self.filter_warnings(): result.test_run(test) return result if __name__ == '__main__': module = sys.argv[1] sys.argv[1:] = sys.argv[2:] unittest.main(module, testRunner=JSONTestRunner) IRkernel/tests/testthat/test_ir.py0000644000176200001440000003205013512164317017015 0ustar liggesusers# Test manually via # IR_KERNEL_NAME=ir python3 -m test_ir -k some_test import os import sys from pathlib import Path HERE = Path(__file__).parent sys.path.insert(0, str(HERE / 'jkt')) import unittest import jupyter_kernel_test as jkt from jupyter_client.manager import start_new_kernel from jupyter_kernel_test.messagespec import validate_message without_rich_display = '''\ options(jupyter.rich_display = FALSE) {} options(jupyter.rich_display = TRUE) ''' #this will not work! #withr::with_options(list(jupyter.rich_display = FALSE), {}) TIMEOUT = 15 class IRkernelTests(jkt.KernelTests): kernel_name = os.environ.get('IR_KERNEL_NAME', 'testir') language_name = 'R' def _execute_code(self, code, tests=True, silent=False, store_history=True): self.flush_channels() reply, output_msgs = self.execute_helper(code, silent=silent, store_history=store_history) self.assertEqual(reply['content']['status'], 'ok', '{0}: {0}'.format(reply['content'].get('ename'), reply['content'].get('evalue'))) if tests: self.assertGreaterEqual(len(output_msgs), 1) # the irkernel only sends display_data, not execute_results self.assertEqual(output_msgs[0]['msg_type'], 'display_data') return reply, output_msgs code_hello_world = 'print("hello, world")' completion_samples = [ {'text': 'zi', 'matches': {'zip'}}, {'text': 'seq_len(', 'matches': {'length.out = '}}, {'text': 'base::transform(', 'matches': {'`_data` = ', '...'}}, {'text': 'foo(R_system', 'matches': {'R_system_version'}}, {'text': 'version$plat', 'matches': {'version$platform'}}, {'text': 'stats4::AIC@def', 'matches': {'stats4::AIC@default'}}, {'text': 'stats4::AIC@default@ta', 'matches': {'stats4::AIC@default@target'}}, {'text': 'grDevice', 'matches': {'grDevices::'}}, {'text': 'base::abbrev', 'matches': {'base::abbreviate'}}, {'text': 'base::.rowNamesD', 'matches': {'base::`.rowNamesDF<-`'}}, {'text': 'repr:::repr_png.def', 'matches': {'repr:::repr_png.default'}}, {'text': 'repr::format2repr$mark', 'matches': {'repr::format2repr$markdown'}}, ] complete_code_samples = ['1', 'print("hello, world")', 'f <- function(x) {\n x*2\n}'] incomplete_code_samples = ['print("hello', 'f <- function(x) {\n x*2'] code_display_data = [ {'code': '"a"', 'mime': 'text/plain'}, {'code': '"a"', 'mime': 'text/html'}, {'code': '"a"', 'mime': 'text/latex'}, {'code': '1:3', 'mime': 'text/plain'}, {'code': '1:3', 'mime': 'text/html'}, {'code': '1:3', 'mime': 'text/latex'}, {'code': without_rich_display.format('"a"'), 'mime': 'text/plain'}, {'code': without_rich_display.format('1:3'), 'mime': 'text/plain'}, ] def test_display_vector(self): """display of vectors""" code = '1:3' reply, output_msgs = self._execute_code(code) # we currently send those formats: text/plain, text/html, text/latex, and text/markdown data = output_msgs[0]['content']['data'] self.assertEqual(len(data), 4, data.keys()) self.assertEqual(data['text/plain'], '[1] 1 2 3') self.assertIn('text/html', data) # this should not be a test of the repr functionality... self.assertIn('', output_msgs[0]['content']['data']['text/html']) self.assertIn('text/latex', output_msgs[0]['content']['data']) self.assertIn('text/markdown', output_msgs[0]['content']['data']) def test_display_vector_only_plaintext(self): """display of plain text vectors""" code = without_rich_display.format('1:3') reply, output_msgs = self._execute_code(code) data = output_msgs[0]['content']['data'] self.assertEqual(len(data), 1, data.keys()) self.assertEqual(data['text/plain'], '[1] 1 2 3') def test_irkernel_plots(self): """plotting""" code = 'plot(1:3)' reply, output_msgs = self._execute_code(code) # we currently send two formats: png, and text/plain data = output_msgs[0]['content']['data'] self.assertEqual(len(data), 2, data.keys()) self.assertEqual(data['text/plain'], 'plot without title') self.assertIn('image/png', data) # we isolate only svg plots, which are not included in the default types metadata = output_msgs[0]['content']['metadata'] self.assertEqual(len(metadata), 0, metadata.keys()) def test_irkernel_plots_only_PNG(self): """plotting PNG""" # the reset needs to happen in another execute because plots are sent after either # the next plot is opened or everything is executed, not at the time when plot # command is actually happening. # (we have a similar problem with width/... but we worked around it by setting the # appropriate options to the recorderdplot object) code = '''\ old_options <- options(jupyter.plot_mimetypes = c('image/png')) plot(1:3) ''' reply, output_msgs = self._execute_code(code) # Only png, no svg or plain/text data = output_msgs[0]['content']['data'] self.assertEqual(len(data), 1, data.keys()) self.assertIn('image/png', data) # nothing in metadata metadata = output_msgs[0]['content']['metadata'] self.assertEqual(len(metadata), 0, metadata.keys()) # And reset code = 'options(old_options)' reply, output_msgs = self._execute_code(code, tests=False) def test_irkernel_plots_only_SVG(self): # again the reset dance (see PNG) code = '''\ old_options <- options(jupyter.plot_mimetypes = c('image/svg+xml')) plot(1:3) ''' reply, output_msgs = self._execute_code(code) # Only svg, no png or plain/text data = output_msgs[0]['content']['data'] self.assertEqual(len(data), 1, data.keys()) self.assertIn('image/svg+xml', data) # svg output is currently isolated metadata = output_msgs[0]['content']['metadata'] self.assertEqual(len(metadata), 1, metadata.keys()) self.assertEqual(len(metadata['image/svg+xml']), 1) self.assertEqual(metadata['image/svg+xml']['isolated'], True) # And reset code = 'options(old_options)' reply, output_msgs = self._execute_code(code, tests=False) def test_irkernel_plots_without_rich_display(self): code = '''\ options(jupyter.rich_display = FALSE) plot(1:3) ''' reply, output_msgs = self._execute_code(code) # Even with rich output as false, we send plots data = output_msgs[0]['content']['data'] self.assertEqual(len(data), 2, data.keys()) self.assertEqual(data['text/plain'], 'plot without title') self.assertIn('image/png', data) # And reset code = 'options(jupyter.rich_display = TRUE)' reply, output_msgs = self._execute_code(code, tests=False) def test_irkernel_df_default_rich_output(self): """data.frame rich representation""" code = 'data.frame(x = 1:3)' reply, output_msgs = self._execute_code(code) # we currently send three formats: text/plain, html, and latex data = output_msgs[0]['content']['data'] self.assertEqual(len(data), 4, data.keys()) def test_irkernel_df_no_rich_output(self): """data.frame plain representation""" code = ''' options(jupyter.rich_display = FALSE) data.frame(x = 1:3) options(jupyter.rich_display = TRUE) ''' reply, output_msgs = self._execute_code(code) # only text/plain data = output_msgs[0]['content']['data'] self.assertEqual(len(data), 1, data.keys()) def test_html_isolated(self): """HTML isolation""" code = ''' repr_html.full_page <- function(obj) sprintf('%s', obj) structure(0, class = 'full_page') ''' reply, output_msgs = self._execute_code(code) data = output_msgs[0]['content']['data'] self.assertEqual(len(data), 2, data.keys()) self.assertEqual(data['text/html'], '0') metadata = output_msgs[0]['content']['metadata'] self.assertEqual(len(metadata), 1, metadata.keys()) self.assertEqual(len(metadata['text/html']), 1, metadata['text/html'].keys()) self.assertEqual(metadata['text/html']['isolated'], True) def test_in_kernel_set(self): """jupyter.in_kernel option""" reply, output_msgs = self._execute_code('getOption("jupyter.in_kernel")') data = output_msgs[0]['content']['data'] self.assertGreaterEqual(len(data), 1, data.keys()) self.assertEqual(data['text/plain'], '[1] TRUE', data.keys()) def test_warning_message(self): self.flush_channels() reply, output_msgs = self.execute_helper('options(warn=1); warning(simpleWarning("wmsg"))') self.assertEqual(output_msgs[0]['msg_type'], 'stream') self.assertEqual(output_msgs[0]['content']['name'], 'stderr') self.assertEqual(output_msgs[0]['content']['text'], 'Warning message:\n“wmsg”') self.flush_channels() reply, output_msgs = self.execute_helper('options(warn=1); f <- function() warning("wmsg"); f()') self.assertEqual(output_msgs[0]['msg_type'], 'stream') self.assertEqual(output_msgs[0]['content']['name'], 'stderr') self.assertEqual(output_msgs[0]['content']['text'], 'Warning message in f():\n“wmsg”') def test_should_increment_history(self): """properly increments execution history""" code = 'data.frame(x = 1:3)' reply, output_msgs = self._execute_code(code) reply2, output_msgs2 = self._execute_code(code) execution_count_1 = reply['content']['execution_count'] execution_count_2 = reply2['content']['execution_count'] self.assertEqual(execution_count_1 + 1, execution_count_2) def test_should_not_increment_history(self): """Does not increment history if silent is true or store_history is false""" code = 'data.frame(x = 1:3)' reply, output_msgs = self._execute_code(code, store_history=False) reply2, output_msgs2 = self._execute_code(code, store_history=False) reply3, output_msgs3 = self._execute_code(code, tests=False, silent=True) execution_count_1 = reply['content']['execution_count'] execution_count_2 = reply2['content']['execution_count'] execution_count_3 = reply3['content']['execution_count'] self.assertEqual(execution_count_1, execution_count_2) self.assertEqual(execution_count_1, execution_count_3) def test_irkernel_inspects(self): """Test if object inspection works.""" self.flush_channels() def test_token_is_ok(token, preprocess=None, postprocess=None): """Check if inspect_request for the `token` returns a reply. Run code in `preprocess` before requesting if it's given, and `proprocess` after requesting. Currently just test if the kernel replys without an error and not care about its content. Because the contents of inspections are still so arguable. When the requirements for the contents are decided, fix the tests beow and check the contents. """ if preprocess: self._execute_code(preprocess, tests=False) msg_id = self.kc.inspect(token) reply = self.kc.get_shell_msg(timeout=TIMEOUT) validate_message(reply, 'inspect_reply', msg_id) self.assertEqual(reply['content']['status'], 'ok') self.assertTrue(reply['content']['found']) self.assertGreaterEqual(len(reply['content']['data']), 1) if postprocess: self._execute_code(postprocess, tests=False) # Numeric constant test_token_is_ok('1') # Reserved word test_token_is_ok('NULL') # Dataset with a help document test_token_is_ok('iris') # Function with a help document test_token_is_ok('c') # Function name with namespace test_token_is_ok('base::c') # Function not exported from namespace test_token_is_ok('tools:::.Rd2pdf') # User-defined variable test_token_is_ok( 'x', preprocess='x <- 1', postprocess='rm("x")' ) # User-defined function test_token_is_ok( 'f', preprocess='f <- function (x) x + x', postprocess='rm("f")' ) # Object which masks other object in workspace test_token_is_ok( 'c', preprocess='c <- function (x) x + x', postprocess='rm("c")' ) if __name__ == '__main__': unittest.main(verbosity=2) IRkernel/tests/testthat/test_utils.r0000644000176200001440000000120113142351436017345 0ustar liggesuserscontext('utils') library(evaluate) test_that('skip_repeated works', { stack <- c('foo()', 'f()', 'f()', 'f()', 'f()', 'bar()') expect_equal(skip_repeated(stack), c('foo()', 'f()', ellip_h, 'f()', 'bar()')) }) test_that('skip_repeated does not skip three or less consecutive items', { stack <- c('foo()', 'f()', 'f()', 'f()', 'bar()') expect_equal(skip_repeated(stack), stack) }) test_that('skip_repeated works on tracebacks', { err <- try_capture_stack(quote({ f <- function(x) stop(x) f(1) }), new.env()) skipped_stack <- skip_repeated(err$calls) expect_is(skipped_stack[[1]], 'call') }) IRkernel/tests/testthat/__pycache__/0000755000176200001440000000000013512164324017200 5ustar liggesusersIRkernel/tests/testthat/__pycache__/test_ir.cpython-37.pyc0000644000176200001440000002357713512164324023316 0ustar liggesusersB (](4@sddlZddlZddlmZeejZejde edddl Z ddl Z ddl mZddlmZdZdZGdd d e jZed kre jd d dS) N)Pathjkt)start_new_kernel)validate_messagezNoptions(jupyter.rich_display = FALSE) {} options(jupyter.rich_display = TRUE) c@s|eZdZejddZdZdJddZdZ d d hd d d hd dddhd ddhd ddhd ddhd ddhd ddhd ddhd ddhd dd hd d!d"hd g Z d#dd$gZ d%d&gZ d'd(d)d'd*d)d'd+d)d,d(d)d,d*d)d,d+d)e d'd(d)e d,d(d)gZd-d.Zd/d0Zd1d2Zd3d4Zd5d6Zd7d8Zd9d:Zd;d<Zd=d>Zd?d@ZdAdBZdCdDZdEdFZdGdHZdIS)K IRkernelTestsZIR_KERNEL_NAMEZtestirRTFc Cs~||j|||d\}}||dddd|dd|dd|rv|t|d||d d d ||fS) N)silent store_historycontentstatusokz{0}: {0}ZenameZevaluermsg_typeZ display_data)flush_channelsexecute_helper assertEqualformatgetassertGreaterEquallen)selfcodetestsr r reply output_msgsr3/home/phil/Dev/R/IRkernel/tests/testthat/test_ir.py _execute_code"s2zIRkernelTests._execute_codezprint("hello, world")Zzizip)textmatcheszseq_len(z length.out = zbase::transform(z `_data` = z...z foo(R_systemZR_system_versionz version$platzversion$platformzstats4::AIC@defzstats4::AIC@defaultzstats4::AIC@default@tazstats4::AIC@default@targetZgrDevicez grDevices::z base::abbrevzbase::abbreviatezbase::.rowNamesDzbase::`.rowNamesDF<-`zrepr:::repr_png.defzrepr:::repr_png.defaultzrepr::format2repr$markzrepr::format2repr$markdown1zf <- function(x) { x*2 }z print("hellozf <- function(x) { x*2z"a"z text/plain)rZmimez text/htmlz text/latexz1:3cCsd}||\}}|ddd}|t|d|||dd|d||d |dddd|d |ddd|d |dddd S) zdisplay of vectorsz1:3rr dataz text/plainz [1] 1 2 3z text/htmlzz text/latexz text/markdownN)rrrkeysassertIn)rrrrr#rrrtest_display_vectorNs z!IRkernelTests.test_display_vectorcCsRtd}||\}}|ddd}|t|d|||dddS) zdisplay of plain text vectorsz1:3rr r#rz text/plainz [1] 1 2 3N)without_rich_displayrrrrr%)rrrrr#rrr"test_display_vector_only_plaintext^s  z0IRkernelTests.test_display_vector_only_plaintextcCs~d}||\}}|ddd}|t|d|||dd|d||ddd }|t|d|d S) Zplottingz plot(1:3)rr r#z text/plainzplot without titlez image/pngmetadataN)rrrr%r&)rrrrr#r+rrrtest_irkernel_plotsfs z!IRkernelTests.test_irkernel_plotscCsd}||\}}|ddd}|t|d||d||ddd}|t|d|d}|j|d d \}}d S) z plotting PNGzj old_options <- options(jupyter.plot_mimetypes = c('image/png')) plot(1:3) rr r#rz image/pngr+zoptions(old_options)F)rN)rrrr%r&)rrrrr#r+rrrtest_irkernel_plots_only_PNGus  z*IRkernelTests.test_irkernel_plots_only_PNGcCsd}||\}}|ddd}|t|d||d||ddd}|t|d||t|dd||ddd d }|j|d d \}}dS) Nzn old_options <- options(jupyter.plot_mimetypes = c('image/svg+xml')) plot(1:3) rr r#rz image/svg+xmlr+isolatedTzoptions(old_options)F)r)rrrr%r&)rrrrr#r+rrrtest_irkernel_plots_only_SVGs z*IRkernelTests.test_irkernel_plots_only_SVGcCsnd}||\}}|ddd}|t|d|||dd|d|d }|j|d d \}}dS) NzP options(jupyter.rich_display = FALSE) plot(1:3) rr r#r*z text/plainzplot without titlez image/pngz$options(jupyter.rich_display = TRUE)F)r)rrrr%r&)rrrrr#rrr(test_irkernel_plots_without_rich_displays z6IRkernelTests.test_irkernel_plots_without_rich_displaycCs<d}||\}}|ddd}|t|d|dS)zdata.frame rich representationzdata.frame(x = 1:3)rr r#r$N)rrrr%)rrrrr#rrr$test_irkernel_df_default_rich_outputsz2IRkernelTests.test_irkernel_df_default_rich_outputcCs<d}||\}}|ddd}|t|d|dS)zdata.frame plain representationz options(jupyter.rich_display = FALSE) data.frame(x = 1:3) options(jupyter.rich_display = TRUE) rr r#rN)rrrr%)rrrrr#rrrtest_irkernel_df_no_rich_outputsz-IRkernelTests.test_irkernel_df_no_rich_outputcCsd}||\}}|ddd}|t|d|||dd|ddd}|t|d ||t|dd |d||dd d d S) zHTML isolationz repr_html.full_page <- function(obj) sprintf('%s', obj) structure(0, class = 'full_page') rr r#r*z text/htmlz0r+rr.TN)rrrr%)rrrrr#r+rrrtest_html_isolatedsz IRkernelTests.test_html_isolatedcCsN|d\}}|ddd}|t|d|||dd|dS) zjupyter.in_kernel optionzgetOption("jupyter.in_kernel")rr r#rz text/plainz[1] TRUEN)rrrr%r)rrrr#rrrtest_in_kernel_setsz IRkernelTests.test_in_kernel_setcCs||d\}}||ddd||dddd||dddd ||d \}}||ddd||dddd||dddd dS) Nz/options(warn=1); warning(simpleWarning("wmsg"))rrstreamr namestderrr uWarning message: “wmsg”z5options(warn=1); f <- function() warning("wmsg"); f()u"Warning message in f(): “wmsg”)rrr)rrrrrrtest_warning_messagesz"IRkernelTests.test_warning_messagecCsLd}||\}}||\}}|dd}|dd}||d|dS)z%properly increments execution historyzdata.frame(x = 1:3)r execution_countrN)rr)rrrrreply2 output_msgs2execution_count_1execution_count_2rrrtest_should_increment_historys   z+IRkernelTests.test_should_increment_historyc Cs|d}|j|dd\}}|j|dd\}}|j|ddd\}}|dd}|dd} |dd} ||| ||| dS) zFDoes not increment history if silent is true or store_history is falsezdata.frame(x = 1:3)F)r T)rr r r9N)rr) rrrrr:r;Zreply3Z output_msgs3r<r=Zexecution_count_3rrr!test_should_not_increment_historys    z/IRkernelTests.test_should_not_increment_historycstdfdd }|d|d|d|d|d|d |d d d d |dddd |dddd dS)z Test if object inspection works.Ncs|rj|ddj|}jjtd}t|d||ddd|ddt |dd d |rj|ddd S) aCheck if inspect_request for the `token` returns a reply. Run code in `preprocess` before requesting if it's given, and `proprocess` after requesting. Currently just test if the kernel replys without an error and not care about its content. Because the contents of inspections are still so arguable. When the requirements for the contents are decided, fix the tests beow and check the contents. F)r)timeoutZ inspect_replyr r r foundr#rN) rZkcinspectZ get_shell_msgTIMEOUTrr assertTruerr)token preprocess postprocessZmsg_idr)rrrtest_token_is_ok s   z>IRkernelTests.test_irkernel_inspects..test_token_is_okr"NULLZirisczbase::cztools:::.Rd2pdfxzx <- 1zrm("x"))rFrGfzf <- function (x) x + xzrm("f")zc <- function (x) x + xzrm("c"))NN)r)rrHr)rrtest_irkernel_inspectss(z$IRkernelTests.test_irkernel_inspectsN)TFT)__name__ __module__ __qualname__osenvironrZ kernel_nameZ language_namerZcode_hello_worldZcompletion_samplesZcomplete_code_samplesZincomplete_code_samplesr(rZcode_display_datar'r)r,r-r/r0r1r2r3r4r8r>r?rMrrrrrsP                  r__main__r*) verbosity)rQsysZpathlibr__file__parentZHEREpathinsertstrunittestZjupyter_kernel_testrZjupyter_client.managerrZjupyter_kernel_test.messagespecrr(rCZ KernelTestsrrNmainrrrrs    *IRkernel/tests/testthat/jkt/0000755000176200001440000000000013572471530015566 5ustar liggesusersIRkernel/tests/testthat/jkt/jupyter_kernel_test/0000755000176200001440000000000013442703421021660 5ustar liggesusersIRkernel/tests/testthat/jkt/jupyter_kernel_test/__init__.py0000644000176200001440000003051613442700337024001 0ustar liggesusers"""Machinery for testing Jupyter kernels via the messaging protocol. """ from unittest import TestCase, SkipTest try: # Python 3 from queue import Empty except ImportError: # Python 2 from Queue import Empty from jupyter_client.manager import start_new_kernel from .messagespec import validate_message, MimeBundle TIMEOUT = 15 __version__ = '0.2.2' class KernelTests(TestCase): kernel_name = "" @classmethod def setUpClass(cls): cls.km, cls.kc = start_new_kernel(kernel_name=cls.kernel_name) @classmethod def tearDownClass(cls): cls.kc.stop_channels() cls.km.shutdown_kernel() def flush_channels(self): for channel in (self.kc.shell_channel, self.kc.iopub_channel): while True: try: msg = channel.get_msg(block=True, timeout=0.1) except Empty: break else: validate_message(msg) language_name = "" file_extension = "" def test_kernel_info(self): self.flush_channels() msg_id = self.kc.kernel_info() reply = self.kc.get_shell_msg(timeout=TIMEOUT) validate_message(reply, 'kernel_info_reply', msg_id) if self.language_name: self.assertEqual(reply['content']['language_info']['name'], self.language_name) if self.file_extension: self.assertEqual(reply['content']['language_info']['file_extension'], self.file_extension) self.assertTrue(reply['content']['language_info']['file_extension'].startswith(".")) def execute_helper(self, code, timeout=TIMEOUT, silent=False, store_history=True): msg_id = self.kc.execute(code=code, silent=silent, store_history=store_history) reply = self.kc.get_shell_msg(timeout=timeout) validate_message(reply, 'execute_reply', msg_id) busy_msg = self.kc.iopub_channel.get_msg(timeout=1) validate_message(busy_msg, 'status', msg_id) self.assertEqual(busy_msg['content']['execution_state'], 'busy') output_msgs = [] while True: msg = self.kc.iopub_channel.get_msg(timeout=0.1) validate_message(msg, msg['msg_type'], msg_id) if msg['msg_type'] == 'status': self.assertEqual(msg['content']['execution_state'], 'idle') break elif msg['msg_type'] == 'execute_input': self.assertEqual(msg['content']['code'], code) continue output_msgs.append(msg) return reply, output_msgs code_hello_world = "" def test_execute_stdout(self): if not self.code_hello_world: raise SkipTest self.flush_channels() reply, output_msgs = self.execute_helper(code=self.code_hello_world) self.assertEqual(reply['content']['status'], 'ok') self.assertGreaterEqual(len(output_msgs), 1) self.assertEqual(output_msgs[0]['msg_type'], 'stream') self.assertEqual(output_msgs[0]['content']['name'], 'stdout') self.assertIn('hello, world', output_msgs[0]['content']['text']) code_stderr = "" def test_execute_stderr(self): if not self.code_stderr: raise SkipTest self.flush_channels() reply, output_msgs = self.execute_helper(code=self.code_stderr) self.assertEqual(reply['content']['status'], 'ok') self.assertGreaterEqual(len(output_msgs), 1) self.assertEqual(output_msgs[0]['msg_type'], 'stream') self.assertEqual(output_msgs[0]['content']['name'], 'stderr') completion_samples = [] def test_completion(self): if not self.completion_samples: raise SkipTest for sample in self.completion_samples: with self.subTest(text=sample['text']): msg_id = self.kc.complete(sample['text']) reply = self.kc.get_shell_msg() validate_message(reply, 'complete_reply', msg_id) if 'matches' in sample: self.assertEqual(set(reply['content']['matches']), set(sample['matches'])) complete_code_samples = [] incomplete_code_samples = [] invalid_code_samples = [] def check_is_complete(self, sample, status): msg_id = self.kc.is_complete(sample) reply = self.kc.get_shell_msg() validate_message(reply, 'is_complete_reply', msg_id) if reply['content']['status'] != status: msg = "For code sample\n {!r}\nExpected {!r}, got {!r}." raise AssertionError(msg.format(sample, status, reply['content']['status'])) def test_is_complete(self): if not (self.complete_code_samples or self.incomplete_code_samples or self.invalid_code_samples): raise SkipTest self.flush_channels() with self.subTest(status="complete"): for sample in self.complete_code_samples: self.check_is_complete(sample, 'complete') with self.subTest(status="incomplete"): for sample in self.incomplete_code_samples: self.check_is_complete(sample, 'incomplete') with self.subTest(status="invalid"): for sample in self.invalid_code_samples: self.check_is_complete(sample, 'invalid') code_page_something = "" def test_pager(self): if not self.code_page_something: raise SkipTest self.flush_channels() reply, output_msgs = self.execute_helper(self.code_page_something) self.assertEqual(reply['content']['status'], 'ok') payloads = reply['content']['payload'] self.assertEqual(len(payloads), 1) self.assertEqual(payloads[0]['source'], 'page') mimebundle = payloads[0]['data'] # Validate the mimebundle MimeBundle().data = mimebundle self.assertIn('text/plain', mimebundle) code_generate_error = "" def test_error(self): if not self.code_generate_error: raise SkipTest self.flush_channels() reply, output_msgs = self.execute_helper(self.code_generate_error) self.assertEqual(reply['content']['status'], 'error') self.assertEqual(len(output_msgs), 1) self.assertEqual(output_msgs[0]['msg_type'], 'error') code_execute_result = [] def test_execute_result(self): if not self.code_execute_result: raise SkipTest for sample in self.code_execute_result: with self.subTest(code=sample['code']): self.flush_channels() reply, output_msgs = self.execute_helper(sample['code']) self.assertEqual(reply['content']['status'], 'ok') self.assertGreaterEqual(len(output_msgs), 1) self.assertEqual(output_msgs[0]['msg_type'], 'execute_result') self.assertIn('text/plain', output_msgs[0]['content']['data']) self.assertEqual(output_msgs[0]['content']['data']['text/plain'], sample['result']) code_display_data = [] def test_display_data(self): if not self.code_display_data: raise SkipTest for sample in self.code_display_data: with self.subTest(code=sample['code']): self.flush_channels() reply, output_msgs = self.execute_helper(sample['code']) self.assertEqual(reply['content']['status'], 'ok') self.assertGreaterEqual(len(output_msgs), 1) self.assertEqual(output_msgs[0]['msg_type'], 'display_data') self.assertIn(sample['mime'], output_msgs[0]['content']['data']) # this should match one of the values in code_execute_result code_history_pattern = "" supported_history_operations = () def history_helper(self, execute_first, timeout=TIMEOUT, **histargs): self.flush_channels() for code in execute_first: reply, output_msgs = self.execute_helper(code) self.flush_channels() msg_id = self.kc.history(**histargs) reply = self.kc.get_shell_msg(timeout=timeout) validate_message(reply, 'history_reply', msg_id) return reply def test_history(self): if not self.code_execute_result: raise SkipTest codes = [s['code'] for s in self.code_execute_result] results = [s['result'] for s in self.code_execute_result] n = len(codes) session = start = None with self.subTest(hist_access_type="tail"): if 'tail' not in self.supported_history_operations: raise SkipTest reply = self.history_helper(codes, output=False, raw=True, hist_access_type="tail", n=n) self.assertEqual(len(reply['content']['history']), n) self.assertEqual(len(reply['content']['history'][0]), 3) self.assertEqual(codes, [h[2] for h in reply['content']['history']]) session, start = reply['content']['history'][0][0:2] with self.subTest(output=True): reply = self.history_helper(codes, output=True, raw=True, hist_access_type="tail", n=n) self.assertEqual(len(reply['content']['history'][0][2]), 2) with self.subTest(hist_access_type="range"): if 'range' not in self.supported_history_operations: raise SkipTest if session is None: raise SkipTest reply = self.history_helper(codes, output=False, raw=True, hist_access_type="range", session=session, start=start, stop=start+1) self.assertEqual(len(reply['content']['history']), 1) self.assertEqual(reply['content']['history'][0][0], session) self.assertEqual(reply['content']['history'][0][1], start) with self.subTest(hist_access_type="search"): if not self.code_history_pattern: raise SkipTest if 'search' not in self.supported_history_operations: raise SkipTest with self.subTest(subsearch="normal"): reply = self.history_helper(codes, output=False, raw=True, hist_access_type="search", pattern=self.code_history_pattern) self.assertGreaterEqual(len(reply['content']['history']), 1) with self.subTest(subsearch="unique"): reply = self.history_helper(codes, output=False, raw=True, hist_access_type="search", pattern=self.code_history_pattern, unique=True) self.assertEqual(len(reply['content']['history']), 1) with self.subTest(subsearch="n"): reply = self.history_helper(codes, output=False, raw=True, hist_access_type="search", pattern=self.code_history_pattern, n=3) self.assertEqual(len(reply['content']['history']), 3) code_inspect_sample = "" def test_inspect(self): if not self.code_inspect_sample: raise SkipTest self.flush_channels() msg_id = self.kc.inspect(self.code_inspect_sample) reply = self.kc.get_shell_msg(timeout=TIMEOUT) validate_message(reply, 'inspect_reply', msg_id) self.assertEqual(reply['content']['status'], 'ok') self.assertTrue(reply['content']['found']) self.assertGreaterEqual(len(reply['content']['data']), 1) code_clear_output = "" def test_clear_output(self): if not self.code_clear_output: raise SkipTest self.flush_channels() reply, output_msgs = self.execute_helper(code=self.code_clear_output) self.assertEqual(reply['content']['status'], 'ok') self.assertGreaterEqual(len(output_msgs), 1) self.assertEqual(output_msgs[0]['msg_type'], 'clear_output') IRkernel/tests/testthat/jkt/jupyter_kernel_test/messagespec.py0000644000176200001440000001003713442700337024535 0ustar liggesusers"""The v5 message specification. This can be used in the tests to verify messages.""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. import sys import nose.tools as nt from traitlets import ( Bool, Unicode, Dict, Integer, List, Enum, ) from .messagespec_common import Reference, MimeBundle, Version # message and header formats specific to verion 5 class RMessage(Reference): msg_id = Unicode() msg_type = Unicode() header = Dict() parent_header = Dict() content = Dict() def check(self, d): super(RMessage, self).check(d) RHeader().check(self.header) if self.parent_header: RHeader().check(self.parent_header) class RHeader(Reference): msg_id = Unicode() msg_type = Unicode() session = Unicode() username = Unicode() version = Version(min='5.0') # version shell replies class ExecuteReply(Reference): execution_count = Integer() status = Enum((u'ok', u'error')) def check(self, d): Reference.check(self, d) if d['status'] == 'ok': ExecuteReplyOkay().check(d) elif d['status'] == 'error': ExecuteReplyError().check(d) class ExecuteReplyOkay(Reference): payload = List(Dict) user_expressions = Dict() class ExecuteReplyError(Reference): ename = Unicode() evalue = Unicode() traceback = List(Unicode) class InspectReply(MimeBundle): found = Bool() class ArgSpec(Reference): args = List(Unicode) varargs = Unicode() varkw = Unicode() defaults = List() class Status(Reference): execution_state = Enum((u'busy', u'idle', u'starting')) class CompleteReply(Reference): matches = List(Unicode) cursor_start = Integer() cursor_end = Integer() status = Unicode() class LanguageInfo(Reference): name = Unicode() version = Unicode(sys.version.split()[0]) class KernelInfoReply(Reference): protocol_version = Version(min='5.0') implementation = Unicode() implementation_version = Version() language_info = Dict() banner = Unicode() def check(self, d): Reference.check(self, d) LanguageInfo().check(d['language_info']) class IsCompleteReply(Reference): status = Enum((u'complete', u'incomplete', u'invalid', u'unknown')) def check(self, d): Reference.check(self, d) if d['status'] == 'incomplete': IsCompleteReplyIncomplete().check(d) class IsCompleteReplyIncomplete(Reference): indent = Unicode() # IOPub messages class ExecuteInput(Reference): code = Unicode() execution_count = Integer() Error = ExecuteReplyError class Stream(Reference): name = Enum((u'stdout', u'stderr')) text = Unicode() class DisplayData(MimeBundle): pass class ExecuteResult(MimeBundle): execution_count = Integer() class HistoryReply(Reference): history = List(List()) class ClearOutput(Reference): wait = Bool() """ Specifications of `content` part of the reply messages. """ references = { 'execute_reply' : ExecuteReply(), 'inspect_reply' : InspectReply(), 'status' : Status(), 'complete_reply' : CompleteReply(), 'kernel_info_reply': KernelInfoReply(), 'is_complete_reply': IsCompleteReply(), 'execute_input' : ExecuteInput(), 'execute_result' : ExecuteResult(), 'history_reply' : HistoryReply(), 'error' : Error(), 'stream' : Stream(), 'display_data' : DisplayData(), 'header' : RHeader(), 'clear_output' : ClearOutput(), } #validation specific to this version of the message specification def validate_message(msg, msg_type=None, parent=None): """validate a message If msg_type and/or parent are given, the msg_type and/or parent msg_id are compared with the given values. """ RMessage().check(msg) if msg_type: nt.assert_equal(msg['msg_type'], msg_type) if parent: nt.assert_equal(msg['parent_header']['msg_id'], parent) content = msg['content'] ref = references[msg['msg_type']] ref.check(content) IRkernel/tests/testthat/jkt/jupyter_kernel_test/__pycache__/0000755000176200001440000000000013442703421024070 5ustar liggesusersIRkernel/tests/testthat/jkt/jupyter_kernel_test/__pycache__/messagespec.cpython-37.pyc0000644000176200001440000001311413442703421031016 0ustar liggesusersB ߀\@sdZddlZddlmZddlmZmZmZm Z m Z m Z ddl m Z mZmZGddde ZGdd d e ZGd d d e ZGd d d e ZGddde ZGdddeZGddde ZGddde ZGddde ZGddde ZGddde ZGddde ZGddde ZGd d!d!e ZeZGd"d#d#e ZGd$d%d%eZ Gd&d'd'eZ!Gd(d)d)e Z"Gd*d+d+e Z#eeeeeeee!e"eee ee#d,Z$d/d-d.Z%dS)0zOThe v5 message specification. This can be used in the tests to verify messages.N)BoolUnicodeDictIntegerListEnum) Reference MimeBundleVersioncs:eZdZeZeZeZeZeZ fddZ Z S)RMessagecs6tt||t|j|jr2t|jdS)N)superr checkRHeaderheader parent_header)selfd) __class__O/home/phil/Dev/R/IRkernel/tests/testthat/jkt/jupyter_kernel_test/messagespec.pyrszRMessage.check) __name__ __module__ __qualname__rmsg_idmsg_typerrrcontentr __classcell__rr)rrr s r c@s.eZdZeZeZeZeZeddZ dS)rz5.0)minN) rrrrrrsessionusernamer versionrrrrrs rc@s"eZdZeZedZddZdS) ExecuteReply)okerrorcCsBt|||ddkr&t|n|ddkr>t|dS)Nstatusr#r$)r rExecuteReplyOkayExecuteReplyError)rrrrrr+s    zExecuteReply.checkN)rrrrexecution_countrr%rrrrrr"'sr"c@seZdZeeZeZdS)r&N)rrrrrpayloaduser_expressionsrrrrr&3sr&c@s eZdZeZeZeeZdS)r'N)rrrrenameevaluer tracebackrrrrr'8sr'c@seZdZeZdS) InspectReplyN)rrrrfoundrrrrr.>sr.c@s&eZdZeeZeZeZeZdS)ArgSpecN) rrrrrargsvarargsvarkwdefaultsrrrrr0Bsr0c@seZdZedZdS)Status)busyidleZstartingN)rrrrexecution_staterrrrr5Isr5c@s&eZdZeeZeZeZeZ dS) CompleteReplyN) rrrrrmatchesrZ cursor_startZ cursor_endr%rrrrr9Msr9c@s$eZdZeZeejdZdS) LanguageInforN)rrrrnamesysr!splitrrrrr;Ssr;c@s6eZdZeddZeZeZeZ eZ ddZ dS)KernelInfoReplyz5.0)rcCs t||t|ddS)N language_info)r rr;)rrrrrr^s zKernelInfoReply.checkN) rrrr protocol_versionrimplementationZimplementation_versionrr@Zbannerrrrrrr?Ws  r?c@seZdZedZddZdS)IsCompleteReply)complete incompleteinvalidunknowncCs(t|||ddkr$t|dS)Nr%rE)r rIsCompleteReplyIncomplete)rrrrrrfs  zIsCompleteReply.checkN)rrrrr%rrrrrrCcsrCc@seZdZeZdS)rHN)rrrrindentrrrrrHksrHc@seZdZeZeZdS) ExecuteInputN)rrrrcoderr(rrrrrJqsrJc@seZdZedZeZdS)Stream)stdoutstderrN)rrrrr<rtextrrrrrLysrLc@s eZdZdS) DisplayDataN)rrrrrrrrP~srPc@seZdZeZdS) ExecuteResultN)rrrrr(rrrrrQsrQc@seZdZeeZdS) HistoryReplyN)rrrrhistoryrrrrrRsrRc@seZdZeZdS) ClearOutputN)rrrrwaitrrrrrTsrT) execute_reply inspect_replyr%complete_replykernel_info_replyis_complete_reply execute_inputexecute_result history_replyr$stream display_datar clear_outputcCsZt||r t|d||r8t|dd||d}t|d}||dS)zvalidate a message If msg_type and/or parent are given, the msg_type and/or parent msg_id are compared with the given values. rrrrN)r rntZ assert_equal references)msgrparentrrefrrrvalidate_messages  rf)NN)&__doc__r=Z nose.toolsZtoolsra traitletsrrrrrrZmessagespec_commonr r r r rr"r&r'r.r0r5r9r;r?rCrHrJErrorrLrPrQrRrTrbrfrrrrsN       IRkernel/tests/testthat/jkt/jupyter_kernel_test/__pycache__/__init__.cpython-37.pyc0000644000176200001440000002216213442703421030261 0ustar liggesusersB ߀\N1@s~dZddlmZmZyddlmZWn ek rDddlmZYnXddlm Z ddl m Z m Z dZ dZGd d d eZd S) zBMachinery for testing Jupyter kernels via the messaging protocol. )TestCaseSkipTest)Empty)start_new_kernel)validate_message MimeBundlez0.2.2c@seZdZdZeddZeddZddZdZdZ dd Z e d d fd d Z dZ ddZdZddZgZddZgZgZgZddZddZdZddZdZddZgZddZgZddZdZ d Z!e fd!d"Z"d#d$Z#dZ$d%d&Z%dZ&d'd(Z'd)S)* KernelTestscCst|jd\|_|_dS)N) kernel_name)rr kmkc)clsrL/home/phil/Dev/R/IRkernel/tests/testthat/jkt/jupyter_kernel_test/__init__.py setUpClassszKernelTests.setUpClasscCs|j|jdS)N)rZ stop_channelsr Zshutdown_kernel)rrrr tearDownClasss zKernelTests.tearDownClassc CsVxP|jj|jjfD]<}x6y|jddd}Wntk r@PYqXt|qWqWdS)NTg?)blocktimeout)rZ shell_channel iopub_channelget_msgrr)selfZchannelmsgrrrflush_channelsszKernelTests.flush_channelscCs||j}|jjtd}t|d||jrL||ddd|j|jr||ddd|j| |ddd ddS)N)rZkernel_info_replycontentZ language_infonamefile_extension.) rrZ kernel_info get_shell_msgTIMEOUTr language_name assertEqualr assertTrue startswith)rmsg_idreplyrrrtest_kernel_info*s  zKernelTests.test_kernel_infoFTc Cs|jj|||d}|jj|d}t|d||jjjdd}t|d|||dddg}xt|jjjd d} t| | d || d dkr|| ddd Pn"| d d kr|| dd |qb|| qbW||fS)N)codesilent store_history)rZ execute_replyrstatusrZexecution_stateZbusyg?msg_typeZidleZ execute_inputr()rZexecuterrrrr"append) rr(rr)r*r%r&Zbusy_msg output_msgsrrrrexecute_helper;s&     zKernelTests.execute_helpercCs|js t||j|jd\}}||ddd|t|d||ddd||ddd d |d |ddd dS) N)r(rr+okrrr,streamrstdoutz hello, worldtext)code_hello_worldrrr/r"assertGreaterEquallenassertIn)rr&r.rrrtest_execute_stdoutWszKernelTests.test_execute_stdoutcCsx|js t||j|jd\}}||ddd|t|d||ddd||ddd d dS) N)r(rr+r0rrr,r1rstderr) code_stderrrrr/r"r5r6)rr&r.rrrtest_execute_stderrgszKernelTests.test_execute_stderrc Cs|js txx|jD]n}|j|ddT|j|d}|j}t|d|d|krv|t|ddt|dWdQRXqWdS)Nr3)r3Zcomplete_replymatchesr) completion_samplesrsubTestrcompleterrr"set)rsampler%r&rrrtest_completionvs   zKernelTests.test_completioncCsT|j|}|j}t|d||dd|krPd}t||||dddS)NZis_complete_replyrr+z/For code sample {!r} Expected {!r}, got {!r}.)rZ is_completerrAssertionErrorformat)rrAr+r%r&rrrrcheck_is_completes    zKernelTests.check_is_completec Cs|js|js|jst||jdd"x|jD]}||dq4WWdQRX|jdd"x|jD]}||dqhWWdQRX|jdd"x|jD]}||dqWWdQRXdS)Nr?)r+Z incompleteinvalid)complete_code_samplesincomplete_code_samplesinvalid_code_samplesrrr>rE)rrArrrtest_is_completes   zKernelTests.test_is_completecCs|js t|||j\}}||ddd|dd}|t|d||ddd|dd }|t_|d |dS) Nrr+r0ZpayloadrrsourceZpagedataz text/plain) code_page_somethingrrr/r"r6rrLr7)rr&r.ZpayloadsZ mimebundlerrr test_pagers  zKernelTests.test_pagercCs^|js t|||j\}}||ddd|t|d||ddddS)Nrr+errorrrr,)code_generate_errorrrr/r"r6)rr&r.rrr test_errorszKernelTests.test_errorc Cs|js tx|jD]}|j|dd|||d\}}||ddd|t|d||ddd |d |ddd ||ddd d |d WdQRXqWdS) Nr()r(rr+r0rrr,Zexecute_resultz text/plainrLresult) code_execute_resultrr>rr/r"r5r6r7)rrAr&r.rrrtest_execute_results zKernelTests.test_execute_resultc Cs|js tx|jD]}|j|ddt|||d\}}||ddd|t|d||ddd ||d |ddd WdQRXqWdS) Nr()r(rr+r0rrr, display_datamimerL) code_display_datarr>rr/r"r5r6r7)rrAr&r.rrrtest_display_datas zKernelTests.test_display_datarcKsX|x|D]}||\}}qW||jjf|}|jj|d}t|d||S)N)rZ history_reply)rr/rhistoryrr)rZ execute_firstrZhistargsr(r&r.r%rrrhistory_helpers  zKernelTests.history_helperc Cs|js tdd|jD}dd|jD}t|}d}}|jddd|jkrVt|j|ddd|d}|t|d d ||t|d d d d ||d d|d d D|d d d d d\}}|jdd:|j|ddd|d}|t|d d d ddWdQRXWdQRX|jddd|jkrLt|dkrZt|j|ddd|||dd}|t|d d d||d d d d |||d d d d|WdQRX|jdd|jstd|jkrt|jdd4|j|ddd|jd}|t|d d dWdQRX|jdd6|j|ddd|jdd}|t|d d dWdQRX|jdd6|j|ddd|jd d}|t|d d d WdQRXWdQRXdS)NcSsg|] }|dqS)r(r).0srrr sz,KernelTests.test_history..cSsg|] }|dqS)rRr)r[r\rrrr]stail)hist_access_typeFT)outputrawr_nrrYrcSsg|] }|dqS)r)r[hrrrr] srd)r`ranger)r`rar_sessionstartstopsearchZnormal)Z subsearch)r`rar_patternunique)r`rar_rkrlrb)r`rar_rkrb) rSrr6r>supported_history_operationsrZr"code_history_patternr5)rcodesresultsrbrgrhr&rrr test_historysj     4    &   " " zKernelTests.test_historycCs||js t||j|j}|jjtd}t|d|||ddd| |dd| t |ddddS) N)r inspect_replyrr+r0foundrLr) code_inspect_samplerrrinspectrr rr"r#r5r6)rr%r&rrr test_inspect:s zKernelTests.test_inspectcCs`|js t||j|jd\}}||ddd|t|d||ddddS) N)r(rr+r0rrr,Z clear_output)code_clear_outputrrr/r"r5r6)rr&r.rrrtest_clear_outputIszKernelTests.test_clear_outputN)(__name__ __module__ __qualname__r classmethodrrrr!rr'r r/r4r8r:r;r=rBrGrHrIrErJrMrNrPrQrSrTrWrXrnrmrZrqrtrvrwrxrrrrr sH        > r N)__doc__unittestrrqueuer ImportErrorZQueuejupyter_client.managerrZ messagespecrrr __version__r rrrrs IRkernel/tests/testthat/jkt/jupyter_kernel_test/__pycache__/messagespec_common.cpython-37.pyc0000644000176200001440000000511313442703421032366 0ustar liggesusersB ߀\@sdZddlZddlmZddlmZddlm Z m Z m Z m Z m Z eedfZGddde ZGdd d e Zed ZGd d d eZdS) z The common code for checking message specification. This can be used in the tests to verify messages. These will remain same between different versions of message specification. N) LooseVersion) HasTraits TraitErrorUnicodeDictobservec@seZdZdZddZdS) Referencea. Base class for message spec specification testing. This class is the core of the message specification test. The idea is that child classes implement trait attributes for each message keys, so that message keys can be tested against these traits using :meth:`check` method. c Csxxr|D]f}t||||dkr(q yt||||Wq tk rn}zds^tt|Wdd}~XYq Xq WdS)z"validate a dict against our traitsNF) trait_namesntZ assert_insetattrrAssertionErrorstr)selfdkeyerV/home/phil/Dev/R/IRkernel/tests/testthat/jkt/jupyter_kernel_test/messagespec_common.pycheck's  zReference.checkN)__name__ __module__ __qualname____doc__rrrrrr s r cs$eZdZfddZddZZS)Versioncs<|dd|_|dd|_|j|d<tt|j||dS)Nminmax default_value)poprrsuperr__init__)rargskwargs) __class__rrr 5s zVersion.__init__cCsX|jr*t|t|jkr*td||jf|jrTt|t|jkrTtd||jfdS)Nzbad version: %s < %szbad version: %s > %s)rVrr)robjvaluerrrvalidate;szVersion.validate)rrrr r' __classcell__rr)r#rr4s rz^[\w\-\+\.]+/[\w\-\+\.]+$c@s(eZdZeZeZedddZdS) MimeBundledatacCs8x2|dD]"\}}t|s$tt|tqWdS)Nnew)itemsmime_patmatchr r Zassert_is_instance string_types)rchangekvrrr _data_changedGszMimeBundle._data_changedN)rrrrmetadatar*rr3rrrrr)Csr))rreZdistutils.versionrr$ nose.toolstoolsr traitletsrrrrrrtyper/r rcompiler-r)rrrrs    IRkernel/tests/testthat/jkt/jupyter_kernel_test/messagespec_common.py0000644000176200001440000000432413442700337026107 0ustar liggesusers""" The common code for checking message specification. This can be used in the tests to verify messages. These will remain same between different versions of message specification. """ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. import re from distutils.version import LooseVersion as V import nose.tools as nt from traitlets import ( HasTraits, TraitError, Unicode, Dict, observe ) string_types = (str, type(u'')) #----------------------------------------------------------------------------- # Message Spec References #----------------------------------------------------------------------------- class Reference(HasTraits): """ Base class for message spec specification testing. This class is the core of the message specification test. The idea is that child classes implement trait attributes for each message keys, so that message keys can be tested against these traits using :meth:`check` method. """ def check(self, d): """validate a dict against our traits""" for key in self.trait_names(): nt.assert_in(key, d) # FIXME: always allow None, probably not a good idea if d[key] is None: continue try: setattr(self, key, d[key]) except TraitError as e: assert False, str(e) class Version(Unicode): def __init__(self, *args, **kwargs): self.min = kwargs.pop('min', None) self.max = kwargs.pop('max', None) kwargs['default_value'] = self.min super(Version, self).__init__(*args, **kwargs) def validate(self, obj, value): if self.min and V(value) < V(self.min): raise TraitError("bad version: %s < %s" % (value, self.min)) if self.max and (V(value) > V(self.max)): raise TraitError("bad version: %s > %s" % (value, self.max)) mime_pat = re.compile(r'^[\w\-\+\.]+/[\w\-\+\.]+$') class MimeBundle(Reference): metadata = Dict() data = Dict() @observe('data') def _data_changed(self, change): for k,v in change['new'].items(): assert mime_pat.match(k) nt.assert_is_instance(v, string_types) IRkernel/tests/testthat/jkt/COPYING.md0000644000176200001440000000542413442700337017221 0ustar liggesusers# Licensing terms This project is licensed under the terms of the Modified BSD License (also known as New or Revised or 3-Clause BSD), as follows: - Copyright (c) 2015-, Jupyter Development Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Jupyter Development Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## About the Jupyter Development Team The Jupyter Development Team is the set of all contributors to the Jupyter project. This includes all of the Jupyter subprojects. The core team that coordinates development on GitHub can be found here: https://github.com/jupyter/. ## Our Copyright Policy Jupyter uses a shared copyright model. Each contributor maintains copyright over their contributions to Jupyter. But, it is important to note that these contributions are typically only changes to the repositories. Thus, the Jupyter source code, in its entirety is not the copyright of any single person or institution. Instead, it is the collective copyright of the entire Jupyter Development Team. If individual contributors want to maintain a record of what changes/contributions they have specific copyright on, they should indicate their copyright in the commit message of the change, when they commit the change to one of the Jupyter repositories. With this in mind, the following banner should be used in any source code file to indicate the copyright and license terms: # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. IRkernel/tests/testthat/test_kernel.r0000644000176200001440000000271013370350506017473 0ustar liggesuserscontext('kernel') get_desc <- function(result) { if (!is.na(result$desc)) result$desc else sub('_', ' ', result$id) } a_test_ran <- FALSE result_to_test <- function(result) { a_test_ran <<- TRUE emit_result <- switch(result$type, success = succeed, expected_failure = succeed, failure = fail, error = stop, unexpected_success = fail, skip = skip, stop('Unknown test result type: ', result$type)) msg <- if (!is.na(result$msg)) result$msg else '' test_that(get_desc(result), emit_result(msg)) } spec_add_status <- tryCatch(installspec(name = 'testir', displayname = 'testir'), error = function(e) 666L) test_that('test kernel installed', { skip_on_cran() expect_equal(spec_add_status, 0L) }) test_that('kernel tests pass', { skip_on_cran() expect_true(file.exists('test_ir.py'), 'test_ir.py exists') Sys.setenv(PYTHONPATH = 'njr') con <- pipe('python3 -W ignore::DeprecationWarning -m ndjson_testrunner test_ir', 'rt') on.exit(expect_equal(close(con), 0L)) jsonlite::stream_in(con, result_to_test, pagesize = 1L, verbose = FALSE) expect_true(a_test_ran, 'at least one python test ran') }) spec_rm_status <- system2('jupyter', c('kernelspec', 'remove', '-f', 'testir')) test_that('test kernel removed', { skip_on_cran() expect_equal(spec_rm_status, 0) }) IRkernel/tests/testthat.R0000644000176200001440000000021213442702626015113 0ustar liggesusers# see https://github.com/hadley/testthat/issues/144 Sys.setenv(R_TESTS = '') library(testthat) library(IRkernel) test_check('IRkernel') IRkernel/R/0000755000176200001440000000000013524511623012170 5ustar liggesusersIRkernel/R/onload.r0000644000176200001440000000014113442702051013617 0ustar liggesusers.onLoad <- function(libname = NULL, pkgname = NULL) { init_options() init_backup_env() } IRkernel/R/environment_runtime.r0000644000176200001440000000044413142351436016464 0ustar liggesusers# This file contains an environment to store runtime variables independent from the kernel runtime_env <- new.env() #' Get global CommManager instance #' #' @return \link{CommManager} instance if a kernel is running, else NULL #' @export comm_manager <- function() runtime_env$comm_manager IRkernel/R/class_unions.r0000644000176200001440000000030313142351436015047 0ustar liggesuserssetClassUnion('functionOrNULL', members = c('function', 'NULL')) setClassUnion('recordedplotOrNULL', members = c('recordedplot', 'NULL')) setClassUnion('listOrNULL', members = c('list', 'NULL')) IRkernel/R/logging.r0000644000176200001440000000426613524511623014011 0ustar liggesusers# The primitive jupyter logging system... # Per default, only error messages are shown # levels: 3 = DEBUG, 2 = INFO/MSG, 1 = ERROR #' Kernel logging functions #' #' A set of exported logging utilities that have the capability to be used in upstream projects. #' Log level and log file can be set via R package options e.g. \code{options(jupyter.log_level = 2L)} #' or from the environment variables JUPYTER_LOG_LEVEL and JUPYTER_LOGFILE. #' #' @param ... message to log #' @name log NULL #' @rdname log #' @export log_debug <- function(...) { if (isTRUE(getOption('jupyter.log_level') >= 3L)) { log_msg('DEBUG', sprintf(...)) } } #' @rdname log #' @export log_info <- function(...) { if (isTRUE(getOption('jupyter.log_level') >= 2L)) { log_msg('INFO', sprintf(...)) } } #' @rdname log #' @export log_error <- function(...) { if (isTRUE(getOption('jupyter.log_level') >= 1L)) { log_msg('ERROR', sprintf(...)) } } log_msg <- function(lvl, msg) { log_msg_stderror(lvl, msg) log_msg_logfile(lvl, msg) } # Handle for stderr to even log to the console when the stderr() points to a # sink'ed connection... .stderror <- stderr() log_msg_stderror <- function(lvl, msg) { cat(sprintf('%s: %s\n', log_color(lvl), msg) , file = .stderror) } #' @importFrom crayon blue #' @importFrom crayon green #' @importFrom crayon red log_color <- function(lvl) { color <- switch(lvl, DEBUG = green, INFO = blue, ERROR = red, stop('unknown level: ', lvl)) color(lvl) } .is_changed_logfile <- local({ old_logfile <- '' function(logfile) { if (old_logfile != logfile) { old_logfile <<- logfile TRUE } else { FALSE } } }) log_msg_logfile <- function(lvl, msg) { cur_logfile <- getOption('jupyter.logfile') if (!is.na(cur_logfile)) { if (.is_changed_logfile(cur_logfile)) { log_msg_stderror('INFO', sprintf('Logging to %s', cur_logfile)) } log_con <- file(cur_logfile, open = 'ab') writeBin(charToRaw(sprintf('%s %s: %s\n', format(Sys.time()), lvl, msg)), log_con, endian = 'little') close(log_con) } } IRkernel/R/utils.r0000644000176200001440000000232613142351436013516 0ustar liggesusersellip_h <- repr:::.char_fallback('\u22EF', '...') #' @importFrom utils head tail skip_repeated <- function(vec) { if (length(vec) == 0L) return(vec) if (is.language(vec[[1]])) { # rle does not work on language items ctb <- as.character(vec) enc <- rle(ctb) enc$values <- match(enc$values, ctb) } else { enc <- rle(vec) } i <- which.max(enc$lengths) l <- enc$lengths[[i]] if (l <= 3) { vec } else { v <- enc$values[[i]] enc$lengths <- c(head(enc$lengths, i - 1), 1, 1, 1, tail(enc$lengths, -i)) enc$values <- c(head(enc$values, i - 1), v, ellip_h, v, tail(enc$values, -i)) inverse.rle(enc) } } fromRawJSON <- function(r) { s <- rawToChar(r) Encoding(s) <- 'UTF-8' fromJSON(s) } set_last_value <- function(obj) { # access via namespace so R CMD check does not complain .BaseNamespaceEnv$unlockBinding(".Last.value", .BaseNamespaceEnv) assign(".Last.value", obj, .BaseNamespaceEnv) lockBinding(".Last.value", .BaseNamespaceEnv) } get_os <- function() switch(.Platform$OS.type, windows = 'win', unix = if (identical(Sys.info()[['sysname']], 'Darwin')) 'osx' else 'unix') IRkernel/R/main.r0000644000176200001440000000114313142351436013276 0ustar liggesusers#' Initialise and run the kernel #' #' @param connection_file The path to the Jupyter connection file, written by the frontend #' #' @export main <- function(connection_file = '') { if (connection_file == '') { # On Windows, passing the connection file in as a string literal fails, # because the \U in C:\Users looks like a unicode escape. So, we have to # pass it as a separate command line argument. connection_file <- commandArgs(TRUE)[[1]] } log_debug('Starting the R kernel...') kernel <- Kernel$new(connection_file = connection_file) kernel$run() } IRkernel/R/compat.r0000644000176200001440000000173613142351436013645 0ustar liggesusersUNICODE_WARNING <- 'Your code contains a unicode char which cannot be displayed in your current locale and R will silently convert it to an escaped form when the R kernel executes this code. This can lead to subtle errors if you use such chars to do comparisons. For more information, please see https://github.com/IRkernel/repr/wiki/Problems-with-unicode-on-windows' #' @importFrom utils capture.output warn_unicode_on_windows <- function(code, warn) { # Workaround to warn user when code contains potential problematic code # https://github.com/IRkernel/repr/issues/28#issuecomment-208810772 # See https://github.com/hadley/evaluate/issues/66 if (.Platform$OS.type == 'windows') { # strip whitespace, because trailing newlines would trip the test... code <- gsub('^\\s+|\\s+$', '', code) real_len <- nchar(code) r_len <- nchar(paste(capture.output(cat(code)), collapse = '\n')) if (real_len != r_len) warn(UNICODE_WARNING) } } IRkernel/R/help.r0000644000176200001440000000433213524511623013305 0ustar liggesusers#' An R kernel for Jupyter. #' #' Jupyter speaks a JSON+ZMQ protocol to a 'kernel' which is responsible for executing code. #' This package is a kernel for the R language. #' #' @section Options: #' #' The following can be set/read via \code{options(opt.name = ...)} / \code{getOption('opt.name')} #' #' \describe{ #' \item{\code{jupyter.log_level}}{1L (errors), 2L (warnings), or 3L (debug). 1L is the default.} #' \item{\code{jupyter.pager_classes}}{Classes to use the pager for instead of displaying them inline. Default: help pages} #' \item{\code{jupyter.in_kernel}}{\code{TRUE} if this code is executed in a running kernel. Set to pretend being/not being in a kernel} #' \item{\code{jupyter.rich_display}}{Use more than just text display} #' \item{\code{jupyter.display_mimetypes}}{ #' The formats emitted when any return value is to be displayed #' (default: all mimetypes listed \href{http://ipython.org/ipython-doc/stable/api/generated/IPython.core.formatters.html#IPython.core.formatters.format_display_data}{here}) #' } #' \item{\code{jupyter.plot_mimetypes}}{ #' The plot formats emitted to the frontend when a plot is displayed. #' (default: image/png and application/pdf) #' } #' \item{\code{jupyter.plot_scale}}{ #' The ratio (notebook PPI / \code{repr.plot.res}). #' E.g.: With the defaults \code{repr.plot.res}=120 px/in (PPI) and \code{jupyter.plot_scale}=2, #' a 1in\eqn{\times}1in image will be displayed as a 0.5in\eqn{\times}0.5in, 240 PPI image. #' (default: 2, fit for retina displays) #' } #' } #' #' @export main #' #' @import methods #' @import uuid #' @import digest #' @importFrom pbdZMQ zmq.ctx.new zmq.socket zmq.bind zmq.getsockopt zmq.setsockopt #' @importFrom pbdZMQ zmq.send zmq.recv zmq.msg.send zmq.msg.recv zmq.send.multipart zmq.recv.multipart #' @importFrom pbdZMQ zmq.poll zmq.poll.get.revents ZMQ.MC #' @importFrom evaluate evaluate new_output_handler parse_all #' @importFrom jsonlite fromJSON toJSON #' @importFrom IRdisplay publish_mimebundle prepare_mimebundle #' @importFrom repr mime2repr repr_option_defaults #' #' @docType package #' @seealso \link{installspec} #' @name IRkernel-package #' @aliases IRkernel IRkernel-package IRkernel-options NULL IRkernel/R/handlers.r0000644000176200001440000000144013142351436014152 0ustar liggesusersprepare_mimebundle_kernel <- function(obj, handle_display_error = log_error) { # we always send text/plain, even if the user removed that from the option! text_bundle <- prepare_mimebundle(obj, 'text/plain', error_handler = handle_display_error) text_repr <- text_bundle$data[['text/plain']] # if the text/plain repr returns nothing, we also do if (is.null(text_repr) || nchar(text_repr) == 0L) return(list(data = NULL, metadata = NULL)) if (getOption('jupyter.rich_display')) { mimetypes <- setdiff(getOption('jupyter.display_mimetypes'), 'text/plain') bundle <- prepare_mimebundle(obj, mimetypes, error_handler = handle_display_error) bundle$data[['text/plain']] <- text_repr bundle } else { text_bundle } } IRkernel/R/environment_shadow.r0000644000176200001440000001144113462034605016266 0ustar liggesusers# Everthing related to the environment which takes functions which shadow base R functions. # This is needed to build in our own needs, like properly shutting down the kernel # when `quit()` is called. add_to_user_searchpath <- function(name, FN, pkg = NULL) { pkg_avail <- !is.null(pkg) && requireNamespace(pkg, quietly = TRUE) if (pkg_avail) { replace_in_package(pkg, name, FN) } else { assign(name, FN, 'jupyter:irkernel') } } replace_in_package <- function(pkg, name, FN) { env_name <- paste0('package:', pkg) if (env_name %in% search()) replace_in_env(name, FN, as.environment(env_name)) replace_in_env(name, FN, getNamespace(pkg)) } replace_in_env <- function(name, FN, env) { .BaseNamespaceEnv$unlockBinding(name, env) assign(name, FN, env) .BaseNamespaceEnv$lockBinding(name, env) } get_shadowenv <- function() { as.environment('jupyter:irkernel') } # save functions that are later replaced (called in .onLoad) backup_env <- new.env() # Circumvent windows build bug, see issue #530 backup_env$utils_flush_console <- function(...) {} # Circumvent devtools bug backup_env$base_flush_connection <- function(...) {} init_backup_env <- function() { if (!identical(environment(utils::flush.console), environment(utils::read.delim))) { tb <- .traceback(2) warning( 'init_backup_env called a second time after init_shadowenv:\n', paste(capture.output(traceback(tb)), collapse = '\n') ) return() } backup_env$base_flush_connection <- base::flush.connection backup_env$utils_flush_console <- utils::flush.console backup_env$base_quit <- base::quit } # Adds functions which do not need any access to the executer into the users searchpath #' @importFrom utils getFromNamespace getS3method #' @importFrom evaluate flush_console init_shadowenv <- function() { # add the accessors to the shadow env itself, so they are actually accessable # from everywhere... add_to_user_searchpath('.irk.get_shadowenv', get_shadowenv) add_to_user_searchpath('.irk.add_to_user_searchpath', add_to_user_searchpath) # For the rest of the functions, please explain why the workaround is needed # (=the problem) and link to the issue describing the problem. # workaround for problems with vignette(xxx) not bringing up the vignette # content in the browser: https://github.com/IRkernel/IRkernel/issues/267 add_to_user_searchpath('print.vignette', function(x, ...) { # R CMD check does not like us using ::: getS3method('print', 'vignette')(x, ...) # returning immediately will run into trouble with zmq and its polling # preventing the vignette server to startup. So wait a little to let # it startup... # 0.1 is too little, so add some margin... Sys.sleep(0.5) }) # we simply have currently no way to view or edit dfs: # https://github.com/IRkernel/IRkernel/issues/280 add_to_user_searchpath('View', function(...) { stop(sQuote('View()'), ' not yet supported in the Jupyter R kernel') }) add_to_user_searchpath('edit', function(...) { stop(sQuote('edit()'), ' not yet supported in the Jupyter R kernel') }) # stream output in loops: # https://github.com/IRkernel/IRkernel/issues/3 replace_in_package('base', 'flush.connection', function(con) { backup_env$base_flush_connection(con) flush_console() }) replace_in_package('utils', 'flush.console', function() { backup_env$utils_flush_console() flush_console() }) } init_cran_repo <- function() { r <- getOption('repos') is_unuseable_mirror <- identical(r, c(CRAN = '@CRAN@')) if (is_unuseable_mirror) { # the default repo according to https://cran.R-project.org/mirrors.html # uses geo-redirects r[['CRAN']] <- 'https://cran.r-project.org' # attribute indicating the repos was set by us... attr(r, 'irkernel') <- TRUE options(repos = r) } } init_session <- function() { init_cran_repo() # We support color even if isatty(stdout()) is FALSE options(crayon.enabled = TRUE) } #' @importFrom grDevices pdf png init_null_device <- function() { # if possible, use a device that # 1. prints no warnings for unicode (unlike pdf/postscript) # 2. can handle /dev/null (unlike OSX devices) # since there is nothing like that on OSX AFAIK, use pdf there (accepting warnings). os <- get_os() ok_device <- switch(os, win = png, osx = pdf, unix = png) null_filename <- switch(os, win = 'NUL', osx = NULL, unix = '/dev/null') null_device <- function(filename = null_filename, ...) ok_device(filename, ...) if (identical(getOption('device'), pdf)) { options(device = null_device) } } IRkernel/R/options.r0000644000176200001440000000263713524511623014056 0ustar liggesusers#' @usage #' jupyter_option_defaults #' #' @rdname IRkernel-package #' @export jupyter_option_defaults <- list( jupyter.rich_display = TRUE, # moved from IRdisplay jupyter.log_level = 1L, jupyter.logfile = NA, jupyter.pager_classes = c( 'packageIQR', 'help_files_with_topic'), jupyter.plot_mimetypes = c( 'text/plain', 'image/png'), jupyter.plot_scale = 2, jupyter.in_kernel = FALSE) from_env <- list( JUPYTER_LOG_LEVEL = as.integer, JUPYTER_LOGFILE = function(f) if (nchar(f) == 0) NA else f) # converts e.g. jupyter.log_level to JUPYTER_LOG_LEVEL opt_to_env <- function(nms) gsub('.', '_', toupper(nms), fixed = TRUE) # called in .onLoad init_options <- function() { for (opt_name in names(jupyter_option_defaults)) { # skip option if it is already set, e.g. in the Rprofile if (is.null(getOption(opt_name))) { # prepare `options` call from the default call_arg <- jupyter_option_defaults[opt_name] # single [] preserve names # if an env var is set, get value from it. env_name <- opt_to_env(opt_name) convert <- from_env[[env_name]] env_val <- Sys.getenv(env_name, unset = NA) if (!is.null(convert) && !is.na(env_val)) call_arg[[opt_name]] <- convert(env_val) do.call(options, call_arg) } } } IRkernel/R/completion.r0000644000176200001440000000452713512164512014532 0ustar liggesuserscompletions <- function(code, cursor_pos = nchar(code), fixup = TRUE) { # Find which line we're on and position within that line lines <- strsplit(code, '\n', fixed = TRUE)[[1]] chars_before_line <- 0L for (line in lines) { new_cursor_pos <- cursor_pos - nchar(line) - 1L # -1 for the newline if (new_cursor_pos < 0L) { break } cursor_pos <- new_cursor_pos chars_before_line <- chars_before_line + nchar(line) + 1L } # the completion docs say: # > they are unexported because they are not meant to be called directly by users # And we are no users, so we just have to trick the overeager R CMD check by not using ::: utils_ns <- asNamespace('utils') get('.assignLinebuffer', utils_ns)(line) get('.assignEnd', utils_ns)(cursor_pos) # .guessTokenFromLine, like most other functions here usually sets variables in .CompletionEnv. # When specifying update = FALSE, it instead returns a list(token = ..., start = ...) c.info <- get('.guessTokenFromLine', utils_ns)(update = FALSE) get('.guessTokenFromLine', utils_ns)() get('.completeToken', utils_ns)() comps <- get('.retrieveCompletions', utils_ns)() if (fixup) comps <- fixup_comps(comps) start_position <- chars_before_line + c.info$start list( comps = comps, start = start_position, end = start_position + nchar(c.info$token) ) } fixup_comps <- function(comps) { # TODO: only do this if we are not in a string or so re_trail <- '=|::' re_lead <- '[\\w\\d._]+(?:\\$|@|:::?)' # TODO: allow foo$`_bar`$baz # split off leading and trailing parts trailing <- gsub(sprintf('^.*?(%s)?$', re_trail), '\\1', comps, perl = TRUE) comps <- gsub(sprintf('(%s)$', re_trail), '', comps, perl = TRUE) leading <- gsub(sprintf('^((%s)*).*?$', re_lead), '\\1', comps, perl = TRUE) comps <- gsub(sprintf('^(%s)+', re_lead), '', comps, perl = TRUE) # wrap non-identifiers with `` # https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Identifiers comps <- gsub('^([_.].*?|.*?[^\\w\\d._].*?|.*?[.]\\d)$', '`\\1`', comps, perl = TRUE) # good coding style for completions trailing <- gsub('=', ' = ', trailing) comps <- paste0(leading, comps, trailing) gsub('^`[.][.][.]` = $', '...', comps) } IRkernel/R/kernel.r0000644000176200001440000003617713512156450013651 0ustar liggesusers#' @include execution.r help.r comm_manager.r logging.r utils.r Kernel <- setRefClass( 'Kernel', fields = list( connection_info = 'list', zmqctx = 'externalptr', sockets = 'list', executor = 'Executor', comm_manager = 'CommManager'), methods = list( hb_reply = function() { data <- zmq.msg.recv(sockets$hb, unserialize = FALSE) zmq.msg.send(data, sockets$hb, serialize = FALSE) }, sign_msg = function(msg_lst) { "Sign messages" concat <- unlist(msg_lst) hmac(connection_info$key, concat, 'sha256') }, wire_to_msg = function(parts) { "Deserialize a message" i <- 1 while (!identical(parts[[i]], charToRaw(''))) { i <- i + 1 } if (!identical(connection_info$key, '')) { signature <- rawToChar(parts[[i + 1]]) expected_signature <- sign_msg(parts[(i + 2):(i + 5)]) stopifnot(identical(signature, expected_signature)) } # Convert the four key parts of the message to strings and parse the JSON header <- fromRawJSON(parts[[i + 2]]) parent_header <- fromRawJSON(parts[[i + 3]]) metadata <- fromRawJSON(parts[[i + 4]]) content <- fromRawJSON(parts[[i + 5]]) # ZMQ routing bits if (i > 1) { identities <- parts[1:(i - 1)] } else { identities <- NULL } list( header = header, parent_header = parent_header, metadata = metadata, content = content, identities = identities) }, msg_to_wire = function(msg) { "Serialize a message" bodyparts <- list( charToRaw(toJSON(msg$header, auto_unbox = TRUE)), charToRaw(toJSON(msg$parent_header, auto_unbox = TRUE)), charToRaw(toJSON(msg$metadata, auto_unbox = TRUE)), charToRaw(toJSON(msg$content, auto_unbox = TRUE))) signature <- sign_msg(bodyparts) c( msg$identities, list(charToRaw('')), list(charToRaw(signature)), bodyparts) }, new_reply = function(msg_type, parent_msg) { "Prepare a reply" header <- list( msg_id = UUIDgenerate(), username = parent_msg$header$username, session = parent_msg$header$session, msg_type = msg_type, version = '5.0') list( header = header, parent_header = parent_msg$header, identities = parent_msg$identities, # Ensure this is {} in JSON, not [] metadata = namedlist()) }, send_response = function(msg_type, parent_msg, socket_name, content) { "Send a response" msg <- new_reply(msg_type, parent_msg) if (grepl('_reply$', msg_type) && is.null(content$status)) { content$status <- 'ok' } msg$content <- content socket <- sockets[[socket_name]] zmq.send.multipart(socket, msg_to_wire(msg), serialize = FALSE) log_debug('Sending msg %s', msg$header$msg_type) }, handle_shell = function() { "React to a shell message coming in" parts <- zmq.recv.multipart(sockets$shell, unserialize = FALSE) msg <- wire_to_msg(parts) # protocol 5.0: send busy/idle around all of these send_response('status', msg, 'iopub', list( execution_state = 'busy')) switch( msg$header$msg_type, comm_info_request = comm_manager$on_comm_info_request(msg), comm_open = comm_manager$on_comm_open(msg), comm_msg = comm_manager$on_comm_msg(msg), comm_close = comm_manager$on_comm_close(msg), execute_request = executor$execute(msg), kernel_info_request = kernel_info(msg), history_request = history(msg), complete_request = complete(msg), is_complete_request = is_complete(msg), inspect_request = inspect(msg), shutdown_request = shutdown(msg), log_debug(c('Got unhandled msg_type:', msg$header$msg_type))) send_response('status', msg, 'iopub', list( execution_state = 'idle')) }, abort_shell_msg = function() { "Send an abort message for an incoming shell request" # See https://github.com/ipython/ipykernel/blob/1d97cb2a04149387a0d2dbea1b3d0af691d8df6c/ipykernel/kernelbase.py#L623 parts <- zmq.recv.multipart(sockets$shell, unserialize = FALSE) msg <- wire_to_msg(parts) log_debug('Aborting msg of type %s', msg$header$msg_type) reply_type <- paste0(unlist(strsplit(msg$header$msg_type, '_'))[1], '_reply') reply_content <- list(status = 'aborted') send_response(reply_type, msg, 'shell', reply_content) log_debug('Aborted msg') }, abort_queued_messages = function() { "Abort all already queued shell messages after an error" log_debug('abort loop: aborted all outstanding msg') while (TRUE) { log_debug('abort loop: before poll') ret <- zmq.poll( c(sockets$shell), # only shell channel c(.pbd_env$ZMQ.PO$POLLIN), # type 0) # zero timeout, only what's already there log_debug('abort loop: after poll') if (bitwAnd(zmq.poll.get.revents(1), .pbd_env$ZMQ.PO$POLLIN)) { log_debug('abort loop: found msg') abort_shell_msg() } else { # no more messages... log_debug('abort loop: breaking') break } } log_debug('abort loop: end') }, handle_stdin = function() { "React to a stdin message coming in" # wait for 'input_reply' response message while (TRUE) { log_debug('stdin loop: beginning') zmq.poll(c(sockets$stdin), # only stdin channel c(.pbd_env$ZMQ.PO$POLLIN)) # type if (bitwAnd(zmq.poll.get.revents(1), .pbd_env$ZMQ.PO$POLLIN)) { log_debug('stdin loop: found msg') parts <- zmq.recv.multipart(sockets$stdin, unserialize = FALSE) msg <- wire_to_msg(parts) return(msg$content$value) } else { # else shouldn't be possible log_error('stdin loop: zmq.poll returned but no message found?') } } }, is_complete = function(request) { "Checks whether the code in the rest is complete" code <- request$content$code message <- tryCatch({ parse_all(code) # the code compiles, so we are complete (either no code at all / only # comments or syntactically correct code) 'complete' }, error = function(e) e$message) # One of 'complete', 'incomplete', 'invalid', 'unknown' status <- if (message == 'complete') { # syntactical complete code 'complete' } else if (grepl(gettext('unexpected end of input', domain = 'R'), message, fixed = TRUE)) { # missing closing parenthesis 'incomplete' } else if (grepl(gettextf('unexpected %s', 'INCOMPLETE_STRING', domain = 'R'), message, fixed = TRUE)) { # missing closing quotes 'incomplete' } else { # all else 'invalid' } content <- list(status = status) if (status == 'incomplete') { # we don't try to guess the indention level and just return zero indention # That's fine because R has braces... :-) # TODO: do some guessing? content <- c(content, indent = '') } send_response('is_complete_reply', request, 'shell', content) }, complete = function(request) { # 5.0 protocol: code <- request$content$code cursor_pos <- request$content$cursor_pos comps <- completions(code, cursor_pos) send_response('complete_reply', request, 'shell', list( matches = as.list(comps$comps), # make single strings not explode into letters metadata = namedlist(), cursor_start = comps$start, cursor_end = comps$end)) }, inspect = function(request) { # 5.0 protocol: code <- request$content$code cursor_pos <- request$content$cursor_pos title_templates <- list( 'text/plain' = '# %s:\n', 'text/html' = '

%s:

\n') # Function to add a section to content. add_new_section <- function(data, section_name, new_data) { for (mime in names(title_templates)) { new_content <- new_data[[mime]] if (is.null(new_content)) next title <- sprintf(title_templates[[mime]], section_name) # use paste0 since sprintf cannot deal with format strings > 8192 bytes data[[mime]] <- paste0(data[[mime]], title, new_content, '\n', sep = '\n') } return(data) } # Get token under the `cursor_pos`. # Since `.guessTokenFromLine()` does not check the characters after `cursor_pos` # check them by a loop. Use get since R CMD check does not like ::: token <- '' for (i in seq(cursor_pos, nchar(code))) { token_candidate <- get('.guessTokenFromLine', asNamespace('utils'))(code, i) if (nchar(token_candidate) == 0) break token <- token_candidate } data <- namedlist() if (nchar(token) != 0) { # In many cases `get(token)` works, but it does not # in the cases such as `token` is a numeric constant or a reserved word. # Therefore `eval()` is used here. obj <- tryCatch(eval(parse(text = token), envir = .GlobalEnv), error = function(e) NULL) class_data <- if (!is.null(obj)) IRdisplay::prepare_mimebundle(class(obj))$data print_data <- if (!is.null(obj)) IRdisplay::prepare_mimebundle(obj)$data # `help(token)` is not used here because it does not works # in the cases `token` is in `pkg::topic`or `pkg:::topic` form. help_data <- tryCatch({ help_obj <- eval(parse(text = paste0('?', token))) IRdisplay::prepare_mimebundle(help_obj)$data }, error = function(e) NULL) # only show help if we have a function if ('function' %in% class(obj) && !is.null(help_data)) { data <- help_data } else {# any of those that are NULL are automatically skipped data <- add_new_section(data, 'Class attribute', class_data) data <- add_new_section(data, 'Printed form', print_data) data <- add_new_section(data, 'Help document', help_data) } } found <- length(data) != 0 send_response('inspect_reply', request, 'shell', list( found = found, data = data, metadata = namedlist())) }, history = function(request) { send_response('history_reply', request, 'shell', list(history = list())) }, kernel_info = function(request) { rversion <- paste0(version$major, '.', version$minor) send_response('kernel_info_reply', request, 'shell', list( protocol_version = '5.0', implementation = 'IRkernel', implementation_version = as.character(packageVersion('IRkernel')), language_info = list( name = 'R', codemirror_mode = 'r', pygments_lexer = 'r', mimetype = 'text/x-r-source', file_extension = '.r', version = rversion), banner = version$version.string)) }, handle_control = function() { log_debug('Control: beginning') parts <- zmq.recv.multipart(sockets$control, unserialize = FALSE) msg <- wire_to_msg(parts) log_debug('Control: recv msg of type %s', msg$header$msg_type) if (msg$header$msg_type == 'shutdown_request') { log_debug('Control: shutdown...') shutdown(msg) } else { log_debug(paste('Unhandled control message, msg_type:', msg$header$msg_type)) } }, shutdown = function(request) { send_response('shutdown_reply', request, 'control', list( restart = request$content$restart)) # Always call the base quit() during shutdown since execution shadows it. backup_env$base_quit('no') # bound during startup in .onLoad }, initialize = function(connection_file) { if (is.character(connection_file)) connection_file <- file(connection_file) connection_info <<- fromJSON(connection_file) stopifnot(connection_info$transport %in% c('tcp', 'ipc')) url <- paste0(connection_info$transport, '://', connection_info$ip) url_with_port <- function(port_name) { sep <- switch(connection_info$transport, tcp = ':', ipc = '-') paste0(url, sep, connection_info[[port_name]]) } # ZMQ Socket setup zmqctx <<- zmq.ctx.new() sockets <<- list( hb = zmq.socket(zmqctx, .pbd_env$ZMQ.ST$REP), iopub = zmq.socket(zmqctx, .pbd_env$ZMQ.ST$PUB), control = zmq.socket(zmqctx, .pbd_env$ZMQ.ST$ROUTER), stdin = zmq.socket(zmqctx, .pbd_env$ZMQ.ST$ROUTER), shell = zmq.socket(zmqctx, .pbd_env$ZMQ.ST$ROUTER)) # Enable handover: https://github.com/IRkernel/IRkernel/issues/508 for (router in sockets[c('control', 'stdin', 'shell')]) { zmq.setsockopt(router, .pbd_env$ZMQ.SO$ROUTER_HANDOVER, 1L) } zmq.bind(sockets$hb, url_with_port('hb_port')) zmq.bind(sockets$iopub, url_with_port('iopub_port')) zmq.bind(sockets$control, url_with_port('control_port')) zmq.bind(sockets$stdin, url_with_port('stdin_port')) zmq.bind(sockets$shell, url_with_port('shell_port')) executor <<- Executor$new( send_response = .self$send_response, handle_stdin = .self$handle_stdin, abort_queued_messages = .self$abort_queued_messages) comm_manager <<- CommManager$new(send_response = .self$send_response) runtime_env$comm_manager <- comm_manager }, run = function() { options(jupyter.in_kernel = TRUE) while (TRUE) { log_debug('main loop: beginning') r <- tryCatch( zmq.poll( c(sockets$hb, sockets$shell, sockets$control), rep(.pbd_env$ZMQ.PO$POLLIN, 3), MC = ZMQ.MC(check.eintr = TRUE)), interrupt = function(e) list(0L, 'SIGINT')) log_debug('main loop: after poll. ZMQ code: %s; Errno: %s', r[[1L]], r[[2L]]) if (identical(r[[2L]], 'SIGINT')) { log_info('main loop: keyboard interrupt caught') next } # It's important that these messages are handled one by one in each # look. The problem is that during the handler, a new zmq.poll could be # done (and is done in case of errors in a execution request) and this # invalidates the zmq.poll.get.revents call leading to "funny" results # with found control message even if there are no control messages. So # the easiest seems to be to handle this in a big if .. else if .. else # clause... # https://github.com/IRkernel/IRkernel/pull/266 if (bitwAnd(zmq.poll.get.revents(1), .pbd_env$ZMQ.PO$POLLIN)) { log_debug('main loop: hb') hb_reply() } else if (bitwAnd(zmq.poll.get.revents(2), .pbd_env$ZMQ.PO$POLLIN)) { log_debug('main loop: shell') handle_shell() } else if (bitwAnd(zmq.poll.get.revents(3), .pbd_env$ZMQ.PO$POLLIN)) { log_debug('main loop: control') handle_control() } else { # else shouldn't be possible log_debug('main loop: zmq.poll returned but no message found?') } } log_debug('main loop: end') }) ) IRkernel/R/execution.r0000644000176200001440000002751113524511623014364 0ustar liggesusers#' @include options.r class_unions.r NULL # Create an empty named list #' @importFrom stats setNames namedlist <- function() setNames(list(), character(0)) # Converts something to a string no matter what #' @importFrom utils str resilient_to_str <- function(v) tryCatch(toString(v), error = function(e) capture.output(str(v))) plot_builds_upon <- function(prev, current) { if (is.null(prev)) { return(TRUE) } lprev <- length(prev[[1]]) lcurrent <- length(current[[1]]) lcurrent >= lprev && identical(current[[1]][1:lprev], prev[[1]][1:lprev]) } ask <- function(prompt = '') { answer <- NA while (is.na(answer)) { answer <- switch(readline(prompt), y = , Y = TRUE, n = , N = FALSE, c = NULL, NA) } answer } format_stack <- function(calls) { line_refs <- rep('', length(calls)) tb <- lapply(seq_along(calls), function(cl) { call <- calls[[cl]] # first_line, first_byte, last_line, last_byte, first_column, last_column, first_parsed, last_parsed ref <- attr(call, 'srcref') filename <- attr(ref, 'srcfile')$filename if (!is.null(ref)) { f <- ref[[1]] l <- ref[[3]] lines <- if (f == l) f else paste0(f, '-', l) line_refs[[cl]] <<- paste0(' # at line ', lines, ' of file ', filename) } white <- paste(rep(' ', nchar(format(cl))), collapse = '') f.call <- format(call) line.prefix <- c(cl, rep(white, length(f.call) - 1)) paste(paste0(line.prefix, '. ', f.call), collapse = '\n') }) paste0(tb, line_refs) } #' @importFrom utils capture.output Executor <- setRefClass( Class = 'Executor', fields = list( send_response = 'function', handle_stdin = 'function', abort_queued_messages = 'function', execution_count = 'integer', payload = 'list', err = 'list', interrupted = 'logical', last_recorded_plot = 'recordedplotOrNULL', current_request = 'listOrNULL', nframe = 'integer'), methods = list( is_silent = function() { current_request$content$silent }, should_store_history = function() { sh <- current_request$content$store_history !is.null(sh) && sh }, send_error_msg = function(msg) { if (is_silent()) return() send_response('stream', current_request, 'iopub', list(name = 'stderr', text = msg)) }, display_data = function(data, metadata = NULL) { if (is.null(metadata)) { metadata <- namedlist() } send_response('display_data', current_request, 'iopub', list( data = data, metadata = metadata)) invisible(TRUE) }, page = function(mimebundle) { payload <<- c(payload, list(c(source = 'page', mimebundle))) }, # .Last doesn’t seem to work, so replicating behavior quit = function(save = 'default', status = 0, runLast = TRUE) { save <- switch(save, default = , yes = TRUE, no = FALSE, ask = ask('Save workspace image? [y/n/c]: '), stop('unknown `save` value')) if (is.null(save)) return() # cancel if (runLast) { if (!is.null(.GlobalEnv$.Last)) .GlobalEnv$.Last() if (!is.null(.GlobalEnv$.Last.sys)) .GlobalEnv$.Last.sys() } if (save) NULL # TODO: actually save history payload <<- c(.self$payload, list(list(source = 'ask_exit', keepkernel = FALSE))) }, # noninteractive readline = function(prompt = '') { log_debug('entering custom readline') send_response('input_request', current_request, 'stdin', list(prompt = prompt, password = FALSE)) # wait for 'input_reply' response message input <- handle_stdin() }, # noninteractive 5.0 protocol: get_pass = function(prompt = '') { log_debug('entering custom get_pass') send_response('input_request', current_request, 'stdin', list(prompt = prompt, password = TRUE)) # wait for 'input_reply' response message log_debug('exiting custom get_pass') input <- handle_stdin() }, handle_error = function(e) { estr <- resilient_to_str(e) tryCatch({ log_debug('Error output: %s', estr) calls <- head(sys.calls()[-seq_len(nframe + 1L)], -3) calls <- skip_repeated(calls) msg <- paste0(estr, 'Traceback:\n') stack_info <- format_stack(calls) err <<- list(ename = 'ERROR', evalue = estr, traceback = as.list(c(msg, stack_info))) if (!is_silent()) { send_response('error', current_request, 'iopub', err) } }, error = function(e2) { log_error('Error in handle_error! %s', resilient_to_str(e2)) log_error('Caused when handling %s', estr) }) }, send_plot = function(plotobj) { formats <- namedlist() metadata <- namedlist() for (mime in getOption('jupyter.plot_mimetypes')) { w <- attr(plotobj, '.irkernel_width') h <- attr(plotobj, '.irkernel_height') ppi <- attr(plotobj, '.irkernel_ppi') tryCatch({ formats[[mime]] <- mime2repr[[mime]](plotobj, w, h) }, error = handle_error) metadata[[mime]] <- list( width = w * ppi, height = h * ppi ) # Isolating SVGs (putting them in an iframe) avoids strange # interactions with CSS on the page. if (identical(mime, 'image/svg+xml')) { metadata[[mime]]$isolated <- TRUE } } publish_mimebundle(formats, metadata) }, handle_display_error = function(e) { # This is used with withCallingHandler and only has two additional # calls at the end instead of the 3 for tryCatch... (-2 at the end) # we also remove the tryCatch and mime2repr stuff at the head of the callstack (+7) calls <- head(sys.calls()[-seq_len(nframe + 7L)], -2) stack_info <- format_stack(calls) msg <- sprintf('ERROR while rich displaying an object: %s\nTraceback:\n%s\n', toString(e), paste(stack_info, collapse = '\n')) log_debug(msg) send_error_msg(msg) }, handle_value = function(obj, visible) { log_debug('Value output...') set_last_value(obj) if (!visible) return() mimebundle <- prepare_mimebundle_kernel(obj, .self$handle_display_error) if (is.null(mimebundle$data)) return() if (length(intersect(class(obj), getOption('jupyter.pager_classes'))) > 0) { log_debug('Showing pager: %s', paste(capture.output(str(mimebundle$data)), collapse = '\n')) page(mimebundle) } else { log_debug('Sending display_data: %s', paste(capture.output(str(mimebundle$data)), collapse = '\n')) send_response('display_data', current_request, 'iopub', mimebundle) } }, stream = function(output, streamname) { log_debug('Stream output: %s', output) send_response('stream', current_request, 'iopub', list( name = streamname, text = paste(output, collapse = '\n'))) }, handle_graphics = function(plotobj) { log_debug('Graphics output...') if (!plot_builds_upon(last_recorded_plot, plotobj)) { log_debug('Sending plot...') send_plot(last_recorded_plot) } # need to be set here to capture the size and have it available when the plot is sent attr(plotobj, '.irkernel_width') <- getOption('repr.plot.width', repr_option_defaults$repr.plot.width) attr(plotobj, '.irkernel_height') <- getOption('repr.plot.height', repr_option_defaults$repr.plot.height) attr(plotobj, '.irkernel_ppi') <- getOption('repr.plot.res', repr_option_defaults$repr.plot.res) / getOption('jupyter.plot_scale', jupyter_option_defaults$jupyter.plot_scale) last_recorded_plot <<- plotobj }, handle_message = function(o) { log_debug('Message output: %s', o) stream(paste(c(conditionMessage(o), '\n'), collapse = ''), 'stderr') }, handle_warning = function(o) { call <- conditionCall(o) call <- if (is.null(call)) '' else sprintf(' in %s', deparse(call)[[1]]) msg <- sprintf('Warning message%s:\n%s\n', call, dQuote(conditionMessage(o))) log_debug('Warning output: %s', msg) stream(msg, 'stderr') }, execute = function(request) { send_response('execute_input', request, 'iopub', list( code = request$content$code, execution_count = execution_count)) # Make the current request available to other functions current_request <<- request # reset ... payload <<- list() err <<- list() # shade base::readline replace_in_package('base', 'readline', .self$readline) # shade getPass::getPass add_to_user_searchpath('getPass', .self$get_pass, 'getPass') # shade base::quit replace_in_package('base', 'quit', .self$quit) replace_in_package('base', 'q', .self$quit) # find out stack depth in notebook cell # TODO: maybe replace with a single call on first execute and rest reuse the value? tryCatch(evaluate( 'stop()', stop_on_error = 1L, output_handler = new_output_handler(error = function(e) nframe <<- sys.nframe()))) oh <- if (is_silent()) { new_output_handler( text = identity, graphics = identity, message = identity, warning = identity, error = identity, value = identity) } else { new_output_handler( text = function(o) stream(o, 'stdout'), graphics = .self$handle_graphics, message = .self$handle_message, warning = .self$handle_warning, error = .self$handle_error, value = .self$handle_value) } interrupted <<- FALSE last_recorded_plot <<- NULL log_debug('Executing code: %s', request$content$code) warn_unicode_on_windows(request$content$code, .self$send_error_msg) tryCatch( evaluate( request$content$code, envir = .GlobalEnv, output_handler = oh, stop_on_error = 1L), interrupt = function(cond) interrupted <<- TRUE, error = .self$handle_error) # evaluate does not catch errors in parsing if (!is_silent() && !is.null(last_recorded_plot)) { send_plot(last_recorded_plot) } status <- if (interrupted) 'abort' else if (!is.null(err$ename)) 'error' else 'ok' reply_content <- c( list( status = status, execution_count = execution_count), switch(status, ok = list(payload = payload, user_expressions = namedlist()), error = err)) send_response('execute_reply', request, 'shell', reply_content) if (interrupted || !is.null(err$ename)) { # errors or interrupts should interrupt all currently queued messages, # not only the currently running one... abort_queued_messages() } if (!is_silent() && should_store_history()) { execution_count <<- execution_count + 1L } }, initialize = function(...) { execution_count <<- 1L err <<- list() options(pager = function(files, header, title, delete.file) { text <- title for (path in files) { text <- c(text, header, readLines(path)) } if (delete.file) file.remove(files) data <- list('text/plain' = paste(text, collapse = '\n')) page(list(data=data, metadata=namedlist())) }) options(jupyter.base_display_func = .self$display_data) # Create the shadow env here and detach it finalize # so it's available for the whole lifetime of the kernel. .BaseNamespaceEnv$attach(NULL, name = 'jupyter:irkernel') # Add stuff to the user environment and configure a few options # in the current session init_shadowenv() init_session() init_null_device() callSuper(...) }, finalize = function() { detach('jupyter:irkernel') }) ) IRkernel/R/installspec.r0000644000176200001440000000477213176134666014721 0ustar liggesusers#' Install the kernelspec to tell Jupyter about IRkernel. #' #' This can be called multiple times for different R interpreter, but you have to give a #' different name (and displayname to see a difference in the notebook UI). If the same #' name is give, it will overwrite older versions of the kernel spec with that name! #' #' @param user Install into user directory (\href{https://specifications.freedesktop.org/basedir-spec/latest/ar01s03.html}{\code{$XDG_DATA_HOME}}\code{/jupyter/kernels}) or globally? (default: NULL but treated as TRUE if "prefix" is not specified) #' @param name The name of the kernel (default "ir") #' @param displayname The name which is displayed in the notebook (default: "R") #' @param rprofile (optional) Path to kernel-specific Rprofile (defaults to system-level settings) #' @param prefix (optional) Path to alternate directory to install kernelspec into (default: NULL) #' #' @return Exit code of the \code{jupyter kernelspec install} call. #' #' @export installspec <- function(user = NULL, name = 'ir', displayname = 'R', rprofile = NULL, prefix = NULL) { exit_code <- system2('jupyter', c('kernelspec', '--version'), FALSE, FALSE) if (exit_code != 0) stop('jupyter-client has to be installed but ', dQuote('jupyter kernelspec --version'), ' exited with code ', exit_code, '.\n') # default to 'user' install if neither 'user' or 'prefix' is specified if (is.null(user)) user <- is.null(prefix) if (user && !is.null(prefix)) stop('"user" and "prefix" are mutually exclusive') # make a kernelspec with the current interpreter's absolute path srcdir <- system.file('kernelspec', package = 'IRkernel') tmp_name <- tempfile() dir.create(tmp_name) file.copy(srcdir, tmp_name, recursive = TRUE) spec_path <- file.path(tmp_name, 'kernelspec', 'kernel.json') spec <- fromJSON(spec_path) spec$argv[[1]] <- file.path(R.home('bin'), 'R') spec$display_name <- displayname if (!is.null(rprofile)) { spec$env <- list(R_PROFILE_USER = rprofile) } write(toJSON(spec, pretty = TRUE, auto_unbox = TRUE), file = spec_path) user_flag <- if (user) '--user' else character(0) prefix_flag <- if (!is.null(prefix)) c('--prefix', prefix) else character(0) args <- c('kernelspec', 'install', '--replace', '--name', name, user_flag, prefix_flag, file.path(tmp_name, 'kernelspec')) exit_code <- system2('jupyter', args) unlink(tmp_name, recursive = TRUE) invisible(exit_code) } IRkernel/R/comm_manager.r0000644000176200001440000001705113142351436015004 0ustar liggesusers#' The CommManager #' #' Has methods able to register comms/targets and process comm messages #' #' @include logging.r class_unions.r #' @export CommManager <- setRefClass( 'CommManager', fields = list( send_response = 'function', target_to_handler_map = 'list', commid_to_comm = 'list', parent_request = 'list' ), methods = list( new_comm = function(target_name, comm_id = UUIDgenerate()) { Comm$new(id = comm_id, target_name = target_name, comm_manager = .self) }, register_target = function(target_name, handler_func) target_to_handler_map[[target_name]] <<- handler_func, unregister_target = function(target_name, handler_func) target_to_handler_map[[target_name]] <<- NULL, register_comm = function(comm) commid_to_comm[[comm$id]] <<- comm, unregister_comm = function(comm) commid_to_comm[[comm$id]] <<- NULL, is_comm_registered = function(comm) !is.null(commid_to_comm[[comm$id]]), send_open = function(comm_id, target_name, data, metadata = list()) { send_response('comm_open', parent_request, 'iopub', list( metadata = metadata, comm_id = comm_id, target_name = target_name, data = data )) }, send_msg = function(comm_id, target_name, data, metadata = list()) { send_response('comm_msg', parent_request, 'iopub', list( metadata = metadata, comm_id = comm_id, target_name = target_name, data = data )) }, send_close = function(comm_id, target_name, data, metadata = list()) { send_response('comm_close', parent_request, 'iopub', list( metadata = metadata, comm_id = comm_id, target_name = target_name, data = data )) }, make_comm_list = function(comm_list) { all_comms <- list() for (the_comm in comm_list) { all_comms[[the_comm$id]] <- list(target_name = the_comm$target_name) } all_comms }, #response: #content = { # # A dictionary of the comms, indexed by uuids. # 'comms': { # comm_id_1: { # 'target_name': str, # }, # comm_id_2: { # 'target_name': str, # }, # }, #} on_comm_info_request = function(request) { #If request$content$target_name is provided return all commids registered with that target_name #Else target_name not in the request return all commids accross all targets reply_msg <- list() comms <- list() if ('target_name' %in% names(request$content)) { #reply with comms only for the specified target_name target_name_requested <- request$content$target_name filtered_comms <- Filter(function(x) x$target_name == target_name_requested, commid_to_comm) comms[['comms']] <- make_comm_list(filtered_comms) } else { comms[['comms']] <- make_comm_list(commid_to_comm) } reply_msg[['content']] <- comms send_response('comm_info_reply', request, 'shell', reply_msg) }, #{ # 'comm_id' : 'u-u-i-d', # 'target_name' : 'my_comm', # 'data' : {} # } on_comm_open = function(request) { parent_request <<- request target_name <- request$content$target_name comm_id <- request$content$comm_id if (target_name %in% names(target_to_handler_map)) { # create a comm object comm <- new_comm(target_name, comm_id) register_comm(comm) data <- request$content$data #invoke target handler tryCatch({ target_to_handler_map[[target_name]](comm, data) }, error = function(e) { log_debug('error invoking the handler for target: %s', e) }) } else { log_debug('target_name not found in comm_open') #reply with a comm_close message as target_name not found send_close(comm_id, target_name, list()) } }, #{ # 'comm_id' : 'u-u-i-d', # 'data' : {} #} on_comm_msg = function(request) { parent_request <<- request comm_id <- request$content$comm_id if (comm_id %in% names(commid_to_comm)) { comm <- commid_to_comm[[comm_id]] data <- request$content$data tryCatch({ comm$handle_msg(data) }, error = function(e) { log_debug('error invoking comm handle msg: %s', e) }) } else { log_debug('comm_id not found in comm_msg') } }, #{ # 'comm_id' : 'u-u-i-d', # 'data' : {} #} on_comm_close = function(request) { parent_request <<- request comm_id <- request$content$comm_id if (comm_id %in% names(commid_to_comm)) { comm <- commid_to_comm[[comm_id]] tryCatch({ comm$handle_close() }, error = function(e) { log_debug('error invoking comm handle close: %s', e) }) unregister_comm(comm) } else { log_debug('comm_id not found in comm_msg') } }, initialize = function(...) { callSuper(...) } ) ) #' The Comm #' #' Has methods able to register and handle message callbacks #' #' @export Comm <- setRefClass( 'Comm', fields = list( id = 'character', target_name = 'character', comm_manager = 'CommManager', msg_callback = 'functionOrNULL', close_callback = 'functionOrNULL' ), methods = list( open = function(msg = list()) { if (!comm_manager$is_comm_registered(.self)) { comm_manager$register_comm(.self) comm_manager$send_open(id, target_name, msg) } else { log_debug('Comm already opened!') } }, send = function(msg = list()) { if (comm_manager$is_comm_registered(.self)) { comm_manager$send_msg(id, target_name, msg) } else { log_debug('Comm is not opened. Cannot send!') } }, close = function(msg = list()) { if (comm_manager$is_comm_registered(.self)) { comm_manager$send_close(id, target_name, msg) comm_manager$unregister_comm(.self) } else { log_debug('Comm is already closed!') } }, on_msg = function(a_msg_callback) { msg_callback <<- a_msg_callback }, on_close = function(a_close_callback) { close_callback <<- a_close_callback }, handle_msg = function(msg) { if (!is.null(msg_callback)) { msg_callback(msg) } }, handle_close = function() { if (!is.null(close_callback)) { close_callback() } } ) ) IRkernel/MD50000644000176200001440000000510413572476532012313 0ustar liggesusers13f9f32f3929dbe12ebd371a01368258 *DESCRIPTION 3fd4786bf5351f2b5fa63d036ae8e5b2 *LICENSE fa6852a2341a2ff99833c40becb6c866 *NAMESPACE b1c4f4c93173b0a9ceb834ce9d78bd99 *R/class_unions.r 87f62d7255f43134bdf4f2306748b2f2 *R/comm_manager.r 9dc12cb752cf14ad77d7d85f3cfe5861 *R/compat.r 8e5c061dd2a326b65e325eece0a38635 *R/completion.r 1867fc3e83d2498e396eec07d1fa5847 *R/environment_runtime.r bd5bd2493569e30e014e1e536893aa04 *R/environment_shadow.r 06d346c509faea1ad86d0fc354b64463 *R/execution.r b325c17c1e9cb8eaac03bfd489975690 *R/handlers.r 48b8bbf656213866104d9349f97a5e9c *R/help.r 9ba80ef70dd380a752251ddcb4158ae6 *R/installspec.r 5cb8476cb65f6b363bc19fdea37df990 *R/kernel.r 16623bf1086219b98537e3a8a9f7aa41 *R/logging.r f9fe9f2c0288a1ce30dbce72a0774569 *R/main.r f445441f1ee8d3a8e7bcdc9375654b4b *R/onload.r daae9e89cf9362aec06e6138100ec044 *R/options.r 54a51eff21cfcbf0bde2f8c270e08300 *R/utils.r 8e90c2b3c5186b5f06cab4a3ab91e28e *README.md 53dfb0e6c19b3a09d9856e5fbfe2bf9c *inst/kernelspec/kernel.js f209c9fba50a620fdc8cfabecf3b3d4e *inst/kernelspec/kernel.json 20c1346c7adfcfa2f6ccdc20703fa84d *inst/kernelspec/logo-64x64.png dfb7be9510d7ecfd3c0d0d674addaeb5 *man/Comm-class.Rd 246fffe4a7ce7bb73e3dc5be38780628 *man/CommManager-class.Rd 94f21816c59921b1174a4fdbd5bf2175 *man/IRkernel-package.Rd b55bfa5a99e1a14a2f4660e322c359e3 *man/comm_manager.Rd 82ec9913715c61fdd8833dbd434a4534 *man/installspec.Rd b24db16df7be50d38e8c5382d4afea72 *man/log.Rd ce78f7bdbe1ef4c47a5a3f1b9e02c647 *man/main.Rd 6db253d573f087960e03ca43aee1e2ff *tests/testthat.R 285575d1924a6d400bb42498246d864c *tests/testthat/__pycache__/test_ir.cpython-37.pyc b33ce7cc0a9ad889275ab80a345d9c0c *tests/testthat/jkt/COPYING.md ea2efe5b65a49ab655c889e36149ebeb *tests/testthat/jkt/jupyter_kernel_test/__init__.py 082306aa256999a84d2b9c9870fe75e3 *tests/testthat/jkt/jupyter_kernel_test/__pycache__/__init__.cpython-37.pyc 2a4e98d1d56b1533d27ed020845c4c3b *tests/testthat/jkt/jupyter_kernel_test/__pycache__/messagespec.cpython-37.pyc c868de9a7837dfbdad5909a34868cdc0 *tests/testthat/jkt/jupyter_kernel_test/__pycache__/messagespec_common.cpython-37.pyc 192575797554710da7edd64f4a002b20 *tests/testthat/jkt/jupyter_kernel_test/messagespec.py 538ff67ebb928f31b08d212d58e33aa3 *tests/testthat/jkt/jupyter_kernel_test/messagespec_common.py dccf98a0c409e7dab02f22fc3cd962d0 *tests/testthat/njr/ndjson_testrunner.py be4255ca30b664bee0f14d3e52d12b00 *tests/testthat/test-options.r 5d6be64183a947dbe210b1557a4d5c35 *tests/testthat/test_ir.py 7b08525be780d54dce814bdc7443ca84 *tests/testthat/test_kernel.r bbf735641a644711091fbc909432ef97 *tests/testthat/test_utils.r IRkernel/inst/0000755000176200001440000000000013142351436012744 5ustar liggesusersIRkernel/inst/kernelspec/0000755000176200001440000000000013142360775015105 5ustar liggesusersIRkernel/inst/kernelspec/kernel.js0000644000176200001440000000405413142360775016726 0ustar liggesusersconst cmd_key = /Mac/.test(navigator.platform) ? 'Cmd' : 'Ctrl' const edit_actions = [ { name: 'R Assign', shortcut: 'Alt--', icon: 'fa-long-arrow-left', help: 'R: Inserts the left-assign operator (<-)', handler(cm) { cm.replaceSelection(' <- ') }, }, { name: 'R Pipe', shortcut: `Shift-${cmd_key}-M`, icon: 'fa-angle-right', help: 'R: Inserts the magrittr pipe operator (%>%)', handler(cm) { cm.replaceSelection(' %>% ') }, }, { name: 'R Help', shortcut: 'F1', icon: 'fa-book', help: 'R: Shows the manpage for the item under the cursor', handler(cm, cell) { const {anchor, head} = cm.findWordAt(cm.getCursor()) const word = cm.getRange(anchor, head) const callbacks = cell.get_callbacks() const options = {silent: false, store_history: false, stop_on_error: true} cell.last_msg_id = cell.notebook.kernel.execute(`help(\`${word}\`)`, callbacks, options) }, }, ] const prefix = 'irkernel' function add_edit_shortcut(notebook, actions, keyboard_manager, edit_action) { const {name, shortcut, icon, help, handler} = edit_action const action = { icon, help, help_index : 'zz', handler: () => { const cell = notebook.get_selected_cell() handler(cell.code_mirror, cell) }, } const full_name = actions.register(action, name, prefix) Jupyter.keyboard_manager.edit_shortcuts.add_shortcut(shortcut, full_name) } function render_math(pager, html) { if (!html) return const $container = pager.pager_element.find('#pager-container') $container.find('p[style="text-align: center;"]').map((i, e) => e.outerHTML = `\\[${e.querySelector('i').innerHTML}\\]`) $container.find('i').map((i, e) => e.outerHTML = `\\(${e.innerHTML}\\)`) MathJax.Hub.Queue(['Typeset', MathJax.Hub, $container[0]]) } define(['base/js/namespace'], ({ notebook, actions, keyboard_manager, pager, }) => ({ onload() { edit_actions.forEach(a => add_edit_shortcut(notebook, actions, keyboard_manager, a)) pager.events.on('open_with_text.Pager', (event, {data: {'text/html': html}}) => render_math(pager, html)) }, })) IRkernel/inst/kernelspec/logo-64x64.png0000644000176200001440000002045413142351436017343 0ustar liggesusersPNG  IHDR@@iq AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~ pHYs99`!IDATxZyUŕ{7IE1ƍK04.J@Q>J 2/Lޠf4Nf1Y[i1 uׯFtu{rꜯNs7"Ћ@/"Ћ_*"xErƐ!C RZ{啦C Gf^nP! è< CG! RmR]ap0 >ZѦo}}Һ[ہ):Hh46;2)aښƓ,GI13#" #"R_-a>cr/!$/%,$10A %1@Xfw )^DUՔU(R΄F53)_0@ܘo5sU7YUC#AP'g:C9p[ܵ+tՍmjrc*ަdLP@m q 7\ے onn兢 K`뺴[ /yWFVEE沍RwDi)u#-p7w n+v›|4@Ʒ.Ѹ /r'cuwrr rT=&``S풙f3yRp҂ěIh+!gπVV"bSxHhVx]FY aG_pj>= ?,L\>v\mcL"S݄SJپnߞ~JfH SG0H֒ -z\ԋt+j+?u;W[{ w>9ضG\>B-XDx5#- Zk}ј1cܘDnz9i6d nx/>brŃmzM#͘cmUEm|y 1H2pㄉP DP%+^JGVEe0>o:ڷ%r5uAWf)*%N!ۨ:e_X=Lx̌U';s9tB+p 1RQ)sP50#e}Ʉo|K츔 9IK܀x }Kzi [c/?Y MXhqA 8(1:6_PcxLCOF+lЧBE~4sW&WNcܝŪD@ya #(O9QCdhbyױ)ZfQYsp"$T[Bє;C- yI!LA}G7mrdsI\=G'i@p؁MAb+!!GJoEb.Ʈ Ч4Aq͐|T*7D;-Ƨ5 $6Bx 9)60煼.O U\~L ?oݚ9$ l(j /t/5JHP"9}lӴ]I7g/ʻ^RZ*i汣L׾ڧ[q);_ AէIPyz iDޫ,*x橶e]V}woyghX-$ږXx΋'<@&yf1nQ.gz R> G\DG{;*a?+,`|[l W;}f[*?&@O%7['g6$ n" l?c=l4@΂7'ҙ4bᄑ'in ",_x8FS {t?P9aX @$C{cpPyKRQvAm:<%ւssy)ZL"rڒ*5 A (G/\,($(U籱@%&4]f)f|'ؖ_Qj`-3GQ{1ɡ} V(wVn$S! }W3KqI\QYSo5|Bc$(yIR1I.99^ 2L\Dl@`(I:fYw|;d d'Y hi ѡIbBνƣQBC ~^`>8D_ֱߔ5@Sª ل&sԳAq^u A%C mF0LesQl{F߽7{ #76k6AtOq͒O-8*>p]E~m~ ? lHppgP૤3OUGIkAI#UAIh bO ݡ "o0X4P wǺ