diff --git a/HISTORY.rst b/HISTORY.rst
index e0c0218e9..db4c9d090 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -3,6 +3,13 @@
Release History
---------------
+1.0.2 (2019-02-??)
+++++++++++++++++++++++
+
+**BugFixes**
+- Allow spaces between ``?`` or ``!`` and python or bash command (#189)
+
+
1.0.1 (2019-02-23)
++++++++++++++++++++++
diff --git a/jupytext/contentsmanager.py b/jupytext/contentsmanager.py
index e637df558..1020fa3ea 100644
--- a/jupytext/contentsmanager.py
+++ b/jupytext/contentsmanager.py
@@ -413,6 +413,14 @@ def trust_notebook(self, path):
def rename_file(self, old_path, new_path):
"""Rename the current notebook, as well as its alternative representations"""
+ if old_path not in self.paired_notebooks:
+ try:
+ # we do not know yet if this is a paired notebook (#190)
+ # -> to get this information we open the notebook
+ self.get(old_path, content=True)
+ except Exception:
+ pass
+
if old_path not in self.paired_notebooks:
super(TextFileContentsManager, self).rename_file(old_path, new_path)
return
diff --git a/jupytext/languages.py b/jupytext/languages.py
index 3eea0b542..6c3cf5993 100644
--- a/jupytext/languages.py
+++ b/jupytext/languages.py
@@ -10,6 +10,7 @@
'.cpp': {'language': 'c++', 'comment': '//'},
'.ss': {'language': 'scheme', 'comment': ';;'},
'.clj': {'language': 'clojure', 'comment': ';;'},
+ '.scm': {'language': 'scheme', 'comment': ';;'},
'.sh': {'language': 'bash', 'comment': '#'},
'.q': {'language': 'q', 'comment': '/'}}
diff --git a/jupytext/magics.py b/jupytext/magics.py
index e089abae4..3704673f3 100644
--- a/jupytext/magics.py
+++ b/jupytext/magics.py
@@ -16,7 +16,7 @@
_COMMENT = {_SCRIPT_EXTENSIONS[ext]['language']: _SCRIPT_EXTENSIONS[ext]['comment'] for ext in _SCRIPT_EXTENSIONS}
# Commands starting with a question or exclamation mark have to be escaped
-_PYTHON_HELP_OR_BASH_CMD = re.compile(r"^(# |#)*(\?|!)[A-Za-z]")
+_PYTHON_HELP_OR_BASH_CMD = re.compile(r"^(# |#)*(\?|!)\s*[A-Za-z]")
_PYTHON_MAGIC_CMD = re.compile(r"^(# |#)*({})(\s|$)".format('|'.join(
# posix
diff --git a/jupytext/version.py b/jupytext/version.py
index 8e49dc8eb..86b6eea1f 100644
--- a/jupytext/version.py
+++ b/jupytext/version.py
@@ -1,3 +1,3 @@
"""Jupytext's version number"""
-__version__ = '1.0.1'
+__version__ = '1.0.2-dev'
diff --git a/tests/notebooks/mirror/ipynb_to_percent/Reference Guide for Calysto Scheme.scm b/tests/notebooks/mirror/ipynb_to_percent/Reference Guide for Calysto Scheme.scm
new file mode 100644
index 000000000..f0b527eb1
--- /dev/null
+++ b/tests/notebooks/mirror/ipynb_to_percent/Reference Guide for Calysto Scheme.scm
@@ -0,0 +1,443 @@
+;; -*- coding: utf-8 -*-
+;; ---
+;; jupyter:
+;; kernelspec:
+;; display_name: Calysto Scheme (Python)
+;; language: scheme
+;; name: calysto_scheme
+;; ---
+
+;; %% [markdown]
+;;
+;;
Reference Guide for Calysto Scheme
+;;
+;; [Calysto Scheme](https://github.com/Calysto/calysto_scheme) is a real Scheme programming language, with full support for continuations, including call/cc. It can also use all Python libraries. Also has some extensions that make it more useful (stepper-debugger, choose/fail, stack traces), or make it better integrated with Python.
+;;
+;; In Jupyter notebooks, because Calysto Scheme uses [MetaKernel](https://github.com/Calysto/metakernel/blob/master/README.rst), it has a fully-supported set of "magics"---meta-commands for additional functionality. This includes running Scheme in parallel. See all of the [MetaKernel Magics](https://github.com/Calysto/metakernel/blob/master/metakernel/magics/README.md).
+;;
+;; Calysto Scheme is written in Scheme, and then translated into Python (and other backends). The entire functionality lies in a single Python file: https://github.com/Calysto/calysto_scheme/blob/master/calysto_scheme/scheme.py However, you can easily install it (see below).
+;;
+;; Please see [Calysto Scheme Language](Calysto%20Scheme%20Language.ipynb) for more details on the Calysto Scheme language.
+;;
+;; ## Installation
+;;
+;; You can install Calysto Scheme with Python3:
+;;
+;; ```
+;; pip3 install --upgrade calysto-scheme --user -U
+;; python3 -m calysto_kernel install --user
+;; ```
+;;
+;; or in the system kernel folder with:
+;;
+;; ```
+;; sudo pip3 install --upgrade calysto-scheme -U
+;; sudo python3 -m calysto_kernel install
+;; ```
+;;
+;; Change pip3/python3 to use a different pip or Python. The version of Python used will determine how Calysto Scheme is run.
+;;
+;; Use it in the console, qtconsole, or notebook with IPython 3:
+;;
+;; ```
+;; ipython console --kernel calysto_scheme
+;; ipython qtconsole --kernel calysto_scheme
+;; ipython notebook --kernel calysto_scheme
+;; ```
+;;
+;; In addition to all of the following items, Calysto Scheme also has access to all of Python's builtin functions, and all of Python's libraries. For example, you can use `(complex 3 2)` to create a complex number by calling Python's complex function.
+;;
+;; ## Jupyter Enhancements
+;;
+;; When you run Calysto Scheme in Jupyter (console, notebook, qtconsole, etc.) you get:
+;;
+;; * TAB completions of Scheme functions and variable names
+;; * display of rich media
+;; * stepper/debugger
+;; * magics (% macros)
+;; * shell commands (! command)
+;; * LaTeX equations
+;; * LaTeX-style variables
+;; * Python integration
+
+;; %% [markdown]
+;; ### LaTeX-style variables
+;;
+;; Calysto Scheme allows you to use LaTeX-style variables in code. For example, if you type:
+;;
+;; ```
+;; \beta
+;; ```
+;;
+;; with the cursor right after the 'a' in beta, and then press TAB, it will turn into the unicode character:
+;;
+;; ```
+;; β
+;; ```
+;;
+;; There are nearly 1300 different symbols defined (thanks to the Julia language) and documented here:
+;;
+;; http://docs.julialang.org/en/release-0.4/manual/unicode-input/#man-unicode-input
+;;
+;; Calysto Scheme may not implement all of those. Some useful and suggestive ones:
+;;
+;; * \pi - π
+;; * \Pi - Π
+;; * \Sigma - Σ
+;; * \_i - subscript i, such as vectorᵢ
+
+;; %%
+(define α 67)
+
+;; %%
+α
+
+;; %%
+(define i 2)
+(define vectorᵢ (vector-ref (vector 0 6 3 2) i))
+vectorᵢ
+
+;; %% [markdown]
+;; ### Rich media
+
+;; %%
+(import "calysto.display")
+
+;; %%
+(calysto.display.HTML "This is bold, italics, underlined.")
+
+;; %%
+(import "calysto.graphics")
+
+;; %%
+(define canvas (calysto.graphics.Canvas))
+
+;; %%
+(define ball (calysto.graphics.Circle '(150 150) 100))
+
+;; %%
+(ball.draw canvas)
+
+;; %% [markdown]
+;; ### Shell commands
+
+;; %%
+! ls /tmp
+
+;; %% [markdown]
+;; ### Stepper/Debugger
+;;
+;; Here is what the debugger looks like:
+;;
+;;
+;;
+;; It has breakpoints (click in left margin). You must press Stop to exit the debugger.
+
+;; %% [markdown]
+;; ```scheme
+;; %%debug
+;;
+;; (begin
+;; (define x 1)
+;; (set! x 2)
+;; )
+;; ```
+
+;; %% [markdown]
+;; ### Python Integration
+;;
+;; You can import and use any Python library in Calysto Scheme.
+;;
+;; In addition, if you wish, you can execute expressions and statements in a Python environment:
+
+;; %%
+(python-eval "1 + 2")
+
+;; %%
+(python-exec
+"
+def mypyfunc(a, b):
+ return a * b
+")
+
+;; %% [markdown]
+;; This is a shared environment with Scheme:
+
+;; %%
+(mypyfunc 4 5)
+
+;; %% [markdown]
+;; You can use `func` to turn a Scheme procedure into a Python function, and `define!` to put it into the shared enviornment with Python:
+
+;; %%
+(define! mypyfunc2 (func (lambda (n) n)))
+
+;; %%
+(python-eval "mypyfunc2(34)")
+
+;; %% [markdown]
+;; # Differences Between Languages
+;;
+;; ## Major differences between Scheme and Python
+;;
+;; 1. In Scheme, double quotes are used for strings and may contain newlines
+;; 1. In Scheme, a single quote is short for (quote ...) and means "literal"
+;; 1. In Scheme, everything is an expression and has a return value
+;; 1. Python does not support macros (e.g., extending syntax)
+;; 1. In Python, "if X" is false if X is None, False, [], (,) or 0. In Scheme, "if X" is only false if X is #f or 0
+;; 1. Calysto Scheme uses continuations, not the call stack. However, for debugging there is a pseudo-stack when an error is raised. You can trun that off with (use-stack-trace #f)
+;; 1. Scheme procedures are not Python functions, but there are means to use one as the other.
+;;
+;; ## Major Differences Between Calysto Scheme and other Schemes
+;;
+;; 1. define-syntax works slightly differently
+;; 1. In Calysto Scheme, #(...) is short for '#(...)
+;; 1. Calysto Scheme is missing many standard functions (see list at bottom)
+;; 1. Calysto Scheme has a built-in amb operator called `choose`
+;; 1. For debugging there is a pseudo-stack when errors are raised in Calysto Scheme. You can trun that off with (use-stack-trace #f)
+;;
+;; ### Stack Trace
+;;
+;; Calysto Scheme acts as if it has a call stack, for easier debugging. For example:
+
+;; %%
+(define fact
+ (lambda (n)
+ (if (= n 1)
+ q
+ (* n (fact (- n 1))))))
+
+;; %%
+(fact 5)
+
+;; %% [markdown]
+;; To turn off the stack trace on error:
+;;
+;; ```scheme
+;; (use-stack-trace #f)
+;; ```
+;; That will allow infinite recursive loops without keeping track of the "stack".
+
+;; %% [markdown]
+;; # Calysto Scheme Variables
+;;
+;; ## SCHEMEPATH
+;; SCHEMEPATH is a list of search directories used with (load NAME). This is a reference, so you should append to it rather than attempting to redefine it.
+
+;; %%
+SCHEMEPATH
+
+;; %%
+(set-cdr! (cdr SCHEMEPATH) (list "/var/modules"))
+
+;; %%
+SCHEMEPATH
+
+;; %% [markdown]
+;; ## Getting Started
+;;
+;; Note that you can use the word `lambda` or \lambda and then press [TAB]
+
+;; %%
+(define factorial
+ (λ (n)
+ (cond
+ ((zero? n) 1)
+ (else (* n (factorial (- n 1)))))))
+
+;; %%
+(factorial 5)
+
+;; %% [markdown]
+;; ## define-syntax
+;; (define-syntax NAME RULES): a method for creating macros
+
+;; %%
+(define-syntax time
+ [(time ?exp) (let ((start (current-time)))
+ ?exp
+ (- (current-time) start))])
+
+;; %%
+(time (car '(1 2 3 4)))
+
+;; %%
+;;---------------------------------------------------------------------
+;; collect is like list comprehension in Python
+
+(define-syntax collect
+ [(collect ?exp for ?var in ?list)
+ (filter-map (lambda (?var) ?exp) (lambda (?var) #t) ?list)]
+ [(collect ?exp for ?var in ?list if ?condition)
+ (filter-map (lambda (?var) ?exp) (lambda (?var) ?condition) ?list)])
+
+(define filter-map
+ (lambda (f pred? values)
+ (if (null? values)
+ '()
+ (if (pred? (car values))
+ (cons (f (car values)) (filter-map f pred? (cdr values)))
+ (filter-map f pred? (cdr values))))))
+
+;; %%
+(collect (* n n) for n in (range 10))
+
+;; %%
+(collect (* n n) for n in (range 5 20 3))
+
+;; %%
+(collect (* n n) for n in (range 10) if (> n 5))
+
+;; %%
+;;---------------------------------------------------------------------
+;; for loops
+
+(define-syntax for
+ [(for ?exp times do . ?bodies)
+ (for-repeat ?exp (lambda () . ?bodies))]
+ [(for ?var in ?exp do . ?bodies)
+ (for-iterate1 ?exp (lambda (?var) . ?bodies))]
+ [(for ?var at (?i) in ?exp do . ?bodies)
+ (for-iterate2 0 ?exp (lambda (?var ?i) . ?bodies))]
+ [(for ?var at (?i ?j . ?rest) in ?exp do . ?bodies)
+ (for ?var at (?i) in ?exp do
+ (for ?var at (?j . ?rest) in ?var do . ?bodies))])
+
+(define for-repeat
+ (lambda (n f)
+ (if (< n 1)
+ 'done
+ (begin
+ (f)
+ (for-repeat (- n 1) f)))))
+
+(define for-iterate1
+ (lambda (values f)
+ (if (null? values)
+ 'done
+ (begin
+ (f (car values))
+ (for-iterate1 (cdr values) f)))))
+
+(define for-iterate2
+ (lambda (i values f)
+ (if (null? values)
+ 'done
+ (begin
+ (f (car values) i)
+ (for-iterate2 (+ i 1) (cdr values) f)))))
+
+;; %%
+(define matrix2d
+ '((10 20)
+ (30 40)
+ (50 60)
+ (70 80)))
+
+(define matrix3d
+ '(((10 20 30) (40 50 60))
+ ((70 80 90) (100 110 120))
+ ((130 140 150) (160 170 180))
+ ((190 200 210) (220 230 240))))
+
+;; %%
+(begin
+ (define hello 0)
+ (for 5 times do (set! hello (+ hello 1)))
+ hello
+ )
+
+;; %%
+(for sym in '(a b c d) do (define x 1) (set! x sym) (print x))
+
+;; %%
+(for n in (range 10 20 2) do (print n))
+
+;; %%
+(for n at (i j) in matrix2d do (print (list n 'coords: i j)))
+
+;; %%
+(for n at (i j k) in matrix3d do (print (list n 'coords: i j k)))
+
+;; %%
+(define-syntax scons
+ [(scons ?x ?y) (cons ?x (lambda () ?y))])
+
+(define scar car)
+
+(define scdr
+ (lambda (s)
+ (let ((result ((cdr s))))
+ (set-cdr! s (lambda () result))
+ result)))
+
+(define first
+ (lambda (n s)
+ (if (= n 0)
+ '()
+ (cons (scar s) (first (- n 1) (scdr s))))))
+
+(define nth
+ (lambda (n s)
+ (if (= n 0)
+ (scar s)
+ (nth (- n 1) (scdr s)))))
+
+(define smap
+ (lambda (f s)
+ (scons (f (scar s)) (smap f (scdr s)))))
+
+(define ones (scons 1 ones))
+
+(define nats (scons 0 (combine nats + ones)))
+
+(define combine
+ (lambda (s1 op s2)
+ (scons (op (scar s1) (scar s2)) (combine (scdr s1) op (scdr s2)))))
+
+(define fibs (scons 1 (scons 1 (combine fibs + (scdr fibs)))))
+
+(define facts (scons 1 (combine facts * (scdr nats))))
+
+(define ! (lambda (n) (nth n facts)))
+
+;; %%
+(! 5)
+
+;; %%
+(nth 10 facts)
+
+;; %%
+(nth 20 fibs)
+
+;; %%
+(first 30 fibs)
+
+;; %% [markdown]
+;; ## for-each
+;; (for-each PROCEDURE LIST): apply PROCEDURE to each item in LIST; like `map` but don't return results
+
+;; %%
+(for-each (lambda (n) (print n)) '(3 4 5))
+
+;; %% [markdown]
+;; ## format
+;; (format STRING ITEM ...): format the string with ITEMS as arguments
+
+;; %%
+(format "This uses formatting ~a ~s ~%" 'apple 'apple)
+
+;; %% [markdown]
+;; ## func
+;;
+;; Turns a lambda into a Python function.
+;;
+;; (func (lambda ...))
+
+;; %%
+(func (lambda (n) n))
+
+;; %% [markdown]
+;; ## There's more!
+;;
+;; Please see [Calysto Scheme Language](Calysto%20Scheme%20Language.ipynb) for more details on the Calysto Scheme language.
diff --git a/tests/notebooks/mirror/ipynb_to_script/Reference Guide for Calysto Scheme.scm b/tests/notebooks/mirror/ipynb_to_script/Reference Guide for Calysto Scheme.scm
new file mode 100644
index 000000000..ba044c3bd
--- /dev/null
+++ b/tests/notebooks/mirror/ipynb_to_script/Reference Guide for Calysto Scheme.scm
@@ -0,0 +1,389 @@
+;; -*- coding: utf-8 -*-
+;; ---
+;; jupyter:
+;; kernelspec:
+;; display_name: Calysto Scheme (Python)
+;; language: scheme
+;; name: calysto_scheme
+;; ---
+
+;;
+;; Reference Guide for Calysto Scheme
+;;
+;; [Calysto Scheme](https://github.com/Calysto/calysto_scheme) is a real Scheme programming language, with full support for continuations, including call/cc. It can also use all Python libraries. Also has some extensions that make it more useful (stepper-debugger, choose/fail, stack traces), or make it better integrated with Python.
+;;
+;; In Jupyter notebooks, because Calysto Scheme uses [MetaKernel](https://github.com/Calysto/metakernel/blob/master/README.rst), it has a fully-supported set of "magics"---meta-commands for additional functionality. This includes running Scheme in parallel. See all of the [MetaKernel Magics](https://github.com/Calysto/metakernel/blob/master/metakernel/magics/README.md).
+;;
+;; Calysto Scheme is written in Scheme, and then translated into Python (and other backends). The entire functionality lies in a single Python file: https://github.com/Calysto/calysto_scheme/blob/master/calysto_scheme/scheme.py However, you can easily install it (see below).
+;;
+;; Please see [Calysto Scheme Language](Calysto%20Scheme%20Language.ipynb) for more details on the Calysto Scheme language.
+;;
+;; ## Installation
+;;
+;; You can install Calysto Scheme with Python3:
+;;
+;; ```
+;; pip3 install --upgrade calysto-scheme --user -U
+;; python3 -m calysto_kernel install --user
+;; ```
+;;
+;; or in the system kernel folder with:
+;;
+;; ```
+;; sudo pip3 install --upgrade calysto-scheme -U
+;; sudo python3 -m calysto_kernel install
+;; ```
+;;
+;; Change pip3/python3 to use a different pip or Python. The version of Python used will determine how Calysto Scheme is run.
+;;
+;; Use it in the console, qtconsole, or notebook with IPython 3:
+;;
+;; ```
+;; ipython console --kernel calysto_scheme
+;; ipython qtconsole --kernel calysto_scheme
+;; ipython notebook --kernel calysto_scheme
+;; ```
+;;
+;; In addition to all of the following items, Calysto Scheme also has access to all of Python's builtin functions, and all of Python's libraries. For example, you can use `(complex 3 2)` to create a complex number by calling Python's complex function.
+;;
+;; ## Jupyter Enhancements
+;;
+;; When you run Calysto Scheme in Jupyter (console, notebook, qtconsole, etc.) you get:
+;;
+;; * TAB completions of Scheme functions and variable names
+;; * display of rich media
+;; * stepper/debugger
+;; * magics (% macros)
+;; * shell commands (! command)
+;; * LaTeX equations
+;; * LaTeX-style variables
+;; * Python integration
+
+;; ### LaTeX-style variables
+;;
+;; Calysto Scheme allows you to use LaTeX-style variables in code. For example, if you type:
+;;
+;; ```
+;; \beta
+;; ```
+;;
+;; with the cursor right after the 'a' in beta, and then press TAB, it will turn into the unicode character:
+;;
+;; ```
+;; β
+;; ```
+;;
+;; There are nearly 1300 different symbols defined (thanks to the Julia language) and documented here:
+;;
+;; http://docs.julialang.org/en/release-0.4/manual/unicode-input/#man-unicode-input
+;;
+;; Calysto Scheme may not implement all of those. Some useful and suggestive ones:
+;;
+;; * \pi - π
+;; * \Pi - Π
+;; * \Sigma - Σ
+;; * \_i - subscript i, such as vectorᵢ
+
+(define α 67)
+
+α
+
+(define i 2)
+(define vectorᵢ (vector-ref (vector 0 6 3 2) i))
+vectorᵢ
+
+;; ### Rich media
+
+(import "calysto.display")
+
+(calysto.display.HTML "This is bold, italics, underlined.")
+
+(import "calysto.graphics")
+
+(define canvas (calysto.graphics.Canvas))
+
+(define ball (calysto.graphics.Circle '(150 150) 100))
+
+(ball.draw canvas)
+
+;; ### Shell commands
+
+! ls /tmp
+
+;; ### Stepper/Debugger
+;;
+;; Here is what the debugger looks like:
+;;
+;;
+;;
+;; It has breakpoints (click in left margin). You must press Stop to exit the debugger.
+
+;; ```scheme
+;; ;; %%debug
+;;
+;; (begin
+;; (define x 1)
+;; (set! x 2)
+;; )
+;; ```
+
+;; ### Python Integration
+;;
+;; You can import and use any Python library in Calysto Scheme.
+;;
+;; In addition, if you wish, you can execute expressions and statements in a Python environment:
+
+(python-eval "1 + 2")
+
+(python-exec
+"
+def mypyfunc(a, b):
+ return a * b
+")
+
+;; This is a shared environment with Scheme:
+
+(mypyfunc 4 5)
+
+;; You can use `func` to turn a Scheme procedure into a Python function, and `define!` to put it into the shared enviornment with Python:
+
+(define! mypyfunc2 (func (lambda (n) n)))
+
+(python-eval "mypyfunc2(34)")
+
+;; # Differences Between Languages
+;;
+;; ## Major differences between Scheme and Python
+;;
+;; 1. In Scheme, double quotes are used for strings and may contain newlines
+;; 1. In Scheme, a single quote is short for (quote ...) and means "literal"
+;; 1. In Scheme, everything is an expression and has a return value
+;; 1. Python does not support macros (e.g., extending syntax)
+;; 1. In Python, "if X" is false if X is None, False, [], (,) or 0. In Scheme, "if X" is only false if X is #f or 0
+;; 1. Calysto Scheme uses continuations, not the call stack. However, for debugging there is a pseudo-stack when an error is raised. You can trun that off with (use-stack-trace #f)
+;; 1. Scheme procedures are not Python functions, but there are means to use one as the other.
+;;
+;; ## Major Differences Between Calysto Scheme and other Schemes
+;;
+;; 1. define-syntax works slightly differently
+;; 1. In Calysto Scheme, #(...) is short for '#(...)
+;; 1. Calysto Scheme is missing many standard functions (see list at bottom)
+;; 1. Calysto Scheme has a built-in amb operator called `choose`
+;; 1. For debugging there is a pseudo-stack when errors are raised in Calysto Scheme. You can trun that off with (use-stack-trace #f)
+;;
+;; ### Stack Trace
+;;
+;; Calysto Scheme acts as if it has a call stack, for easier debugging. For example:
+
+(define fact
+ (lambda (n)
+ (if (= n 1)
+ q
+ (* n (fact (- n 1))))))
+
+(fact 5)
+
+;; To turn off the stack trace on error:
+;;
+;; ```scheme
+;; (use-stack-trace #f)
+;; ```
+;; That will allow infinite recursive loops without keeping track of the "stack".
+
+;; # Calysto Scheme Variables
+;;
+;; ## SCHEMEPATH
+;; SCHEMEPATH is a list of search directories used with (load NAME). This is a reference, so you should append to it rather than attempting to redefine it.
+
+SCHEMEPATH
+
+(set-cdr! (cdr SCHEMEPATH) (list "/var/modules"))
+
+SCHEMEPATH
+
+;; ## Getting Started
+;;
+;; Note that you can use the word `lambda` or \lambda and then press [TAB]
+
+(define factorial
+ (λ (n)
+ (cond
+ ((zero? n) 1)
+ (else (* n (factorial (- n 1)))))))
+
+(factorial 5)
+
+;; ## define-syntax
+;; (define-syntax NAME RULES): a method for creating macros
+
+(define-syntax time
+ [(time ?exp) (let ((start (current-time)))
+ ?exp
+ (- (current-time) start))])
+
+(time (car '(1 2 3 4)))
+
+;; +
+;;---------------------------------------------------------------------
+;; collect is like list comprehension in Python
+
+(define-syntax collect
+ [(collect ?exp for ?var in ?list)
+ (filter-map (lambda (?var) ?exp) (lambda (?var) #t) ?list)]
+ [(collect ?exp for ?var in ?list if ?condition)
+ (filter-map (lambda (?var) ?exp) (lambda (?var) ?condition) ?list)])
+
+(define filter-map
+ (lambda (f pred? values)
+ (if (null? values)
+ '()
+ (if (pred? (car values))
+ (cons (f (car values)) (filter-map f pred? (cdr values)))
+ (filter-map f pred? (cdr values))))))
+;; -
+
+(collect (* n n) for n in (range 10))
+
+(collect (* n n) for n in (range 5 20 3))
+
+(collect (* n n) for n in (range 10) if (> n 5))
+
+;; +
+;;---------------------------------------------------------------------
+;; for loops
+
+(define-syntax for
+ [(for ?exp times do . ?bodies)
+ (for-repeat ?exp (lambda () . ?bodies))]
+ [(for ?var in ?exp do . ?bodies)
+ (for-iterate1 ?exp (lambda (?var) . ?bodies))]
+ [(for ?var at (?i) in ?exp do . ?bodies)
+ (for-iterate2 0 ?exp (lambda (?var ?i) . ?bodies))]
+ [(for ?var at (?i ?j . ?rest) in ?exp do . ?bodies)
+ (for ?var at (?i) in ?exp do
+ (for ?var at (?j . ?rest) in ?var do . ?bodies))])
+
+(define for-repeat
+ (lambda (n f)
+ (if (< n 1)
+ 'done
+ (begin
+ (f)
+ (for-repeat (- n 1) f)))))
+
+(define for-iterate1
+ (lambda (values f)
+ (if (null? values)
+ 'done
+ (begin
+ (f (car values))
+ (for-iterate1 (cdr values) f)))))
+
+(define for-iterate2
+ (lambda (i values f)
+ (if (null? values)
+ 'done
+ (begin
+ (f (car values) i)
+ (for-iterate2 (+ i 1) (cdr values) f)))))
+
+;; +
+(define matrix2d
+ '((10 20)
+ (30 40)
+ (50 60)
+ (70 80)))
+
+(define matrix3d
+ '(((10 20 30) (40 50 60))
+ ((70 80 90) (100 110 120))
+ ((130 140 150) (160 170 180))
+ ((190 200 210) (220 230 240))))
+;; -
+
+(begin
+ (define hello 0)
+ (for 5 times do (set! hello (+ hello 1)))
+ hello
+ )
+
+(for sym in '(a b c d) do (define x 1) (set! x sym) (print x))
+
+(for n in (range 10 20 2) do (print n))
+
+(for n at (i j) in matrix2d do (print (list n 'coords: i j)))
+
+(for n at (i j k) in matrix3d do (print (list n 'coords: i j k)))
+
+;; +
+(define-syntax scons
+ [(scons ?x ?y) (cons ?x (lambda () ?y))])
+
+(define scar car)
+
+(define scdr
+ (lambda (s)
+ (let ((result ((cdr s))))
+ (set-cdr! s (lambda () result))
+ result)))
+
+(define first
+ (lambda (n s)
+ (if (= n 0)
+ '()
+ (cons (scar s) (first (- n 1) (scdr s))))))
+
+(define nth
+ (lambda (n s)
+ (if (= n 0)
+ (scar s)
+ (nth (- n 1) (scdr s)))))
+
+(define smap
+ (lambda (f s)
+ (scons (f (scar s)) (smap f (scdr s)))))
+
+(define ones (scons 1 ones))
+
+(define nats (scons 0 (combine nats + ones)))
+
+(define combine
+ (lambda (s1 op s2)
+ (scons (op (scar s1) (scar s2)) (combine (scdr s1) op (scdr s2)))))
+
+(define fibs (scons 1 (scons 1 (combine fibs + (scdr fibs)))))
+
+(define facts (scons 1 (combine facts * (scdr nats))))
+
+(define ! (lambda (n) (nth n facts)))
+;; -
+
+(! 5)
+
+(nth 10 facts)
+
+(nth 20 fibs)
+
+(first 30 fibs)
+
+;; ## for-each
+;; (for-each PROCEDURE LIST): apply PROCEDURE to each item in LIST; like `map` but don't return results
+
+(for-each (lambda (n) (print n)) '(3 4 5))
+
+;; ## format
+;; (format STRING ITEM ...): format the string with ITEMS as arguments
+
+(format "This uses formatting ~a ~s ~%" 'apple 'apple)
+
+;; ## func
+;;
+;; Turns a lambda into a Python function.
+;;
+;; (func (lambda ...))
+
+(func (lambda (n) n))
+
+;; ## There's more!
+;;
+;; Please see [Calysto Scheme Language](Calysto%20Scheme%20Language.ipynb) for more details on the Calysto Scheme language.
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 6ef6af711..564a118ba 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -15,7 +15,7 @@
from jupytext.compare import compare_notebooks
from jupytext.paired_paths import paired_paths
from jupytext.formats import long_form_one_format, JupytextFormatError
-from .utils import list_notebooks, requires_black, requires_flake8
+from .utils import list_notebooks, requires_black, requires_flake8, skip_if_dict_is_not_ordered
def test_str2bool():
@@ -304,6 +304,7 @@ def test_convert_to_percent_format_and_keep_magics(nb_file, tmpdir):
compare_notebooks(nb1, nb2)
+@skip_if_dict_is_not_ordered
def test_pre_commit_hook(tmpdir):
tmp_ipynb = str(tmpdir.join('nb with spaces.ipynb'))
tmp_py = str(tmpdir.join('nb with spaces.py'))
@@ -334,6 +335,7 @@ def git(*args):
assert os.path.isfile(tmp_py)
+@skip_if_dict_is_not_ordered
def test_pre_commit_hook_py_to_ipynb_and_md(tmpdir):
tmp_ipynb = str(tmpdir.join('nb with spaces.ipynb'))
tmp_py = str(tmpdir.join('nb with spaces.py'))
diff --git a/tests/test_escape_magics.py b/tests/test_escape_magics.py
index 77fb01d71..190f9dc88 100644
--- a/tests/test_escape_magics.py
+++ b/tests/test_escape_magics.py
@@ -107,22 +107,22 @@ def test_force_comment_using_contents_manager(tmpdir):
assert '%pylab inline' in stream.read().splitlines()
-@pytest.mark.parametrize('magic_cmd', ['ls', '!ls', 'ls -al', '!whoami', '# ls', '# mv a b'])
+@pytest.mark.parametrize('magic_cmd', ['ls', '!ls', 'ls -al', '!whoami', '# ls', '# mv a b', '! mkdir tmp'])
def test_comment_bash_commands_in_python(magic_cmd):
- comment_magic([magic_cmd]) == ['# ' + magic_cmd]
- uncomment_magic(['# ' + magic_cmd]) == magic_cmd
+ assert comment_magic([magic_cmd]) == ['# ' + magic_cmd]
+ assert uncomment_magic(['# ' + magic_cmd]) == [magic_cmd]
@pytest.mark.parametrize('not_magic_cmd', ['copy(a)', 'copy.deepcopy'])
def test_do_not_comment_python_cmds(not_magic_cmd):
- comment_magic([not_magic_cmd]) == [not_magic_cmd]
- uncomment_magic([not_magic_cmd]) == not_magic_cmd
+ assert comment_magic([not_magic_cmd]) == [not_magic_cmd]
+ assert uncomment_magic([not_magic_cmd]) == [not_magic_cmd]
@pytest.mark.parametrize('magic_cmd', ['ls', '!ls', 'ls -al', '!whoami', '# ls', '# mv a b'])
def test_do_not_comment_bash_commands_in_R(magic_cmd):
- comment_magic([magic_cmd], language='R') == ['# ' + magic_cmd]
- uncomment_magic(['# ' + magic_cmd], language='R') == magic_cmd
+ assert comment_magic([magic_cmd], language='R') == [magic_cmd]
+ assert uncomment_magic([magic_cmd], language='R') == [magic_cmd]
def test_markdown_image_is_not_magic():
diff --git a/tests/test_mirror.py b/tests/test_mirror.py
index a3a59a097..34c1229ef 100644
--- a/tests/test_mirror.py
+++ b/tests/test_mirror.py
@@ -109,9 +109,12 @@ def test_ipynb_to_r(nb_file):
assert_conversion_same_as_mirror(nb_file, '.low.r', 'ipynb_to_script')
-@pytest.mark.parametrize('nb_file', list_notebooks('ipynb_scheme'))
-def test_ipynb_to_scheme(nb_file):
- assert_conversion_same_as_mirror(nb_file, 'ss', 'ipynb_to_script')
+@pytest.mark.parametrize('nb_file,extension',
+ [(nb_file, extension)
+ for nb_file in list_notebooks('ipynb_scheme')
+ for extension in ('ss', 'scm')])
+def test_ipynb_to_scheme(nb_file, extension):
+ assert_conversion_same_as_mirror(nb_file, extension, 'ipynb_to_script')
@pytest.mark.parametrize('nb_file', list_notebooks('ipynb_clojure'))
@@ -174,9 +177,14 @@ def test_ipynb_to_cpp_percent(nb_file):
assert_conversion_same_as_mirror(nb_file, 'cpp:percent', 'ipynb_to_percent')
-@pytest.mark.parametrize('nb_file', list_notebooks('ipynb_scheme'))
-def test_ipynb_to_scheme_percent(nb_file):
- assert_conversion_same_as_mirror(nb_file, 'ss:percent', 'ipynb_to_percent')
+@pytest.mark.parametrize('nb_file,extension',
+ [(nb_file, extension)
+ for nb_file in list_notebooks('ipynb_scheme')
+ for extension in ('ss', 'scm')])
+def test_ipynb_to_scheme_percent(nb_file, extension):
+ assert_conversion_same_as_mirror(nb_file,
+ '{}:percent'.format(extension),
+ 'ipynb_to_percent')
@pytest.mark.parametrize('nb_file', list_notebooks('ipynb_clojure'))
diff --git a/tests/test_read_simple_percent.py b/tests/test_read_simple_percent.py
index 814c6511d..b16de2774 100644
--- a/tests/test_read_simple_percent.py
+++ b/tests/test_read_simple_percent.py
@@ -189,3 +189,20 @@ def test_multiple_empty_cells():
nb2 = jupytext.reads(text, 'py:percent')
nb2.metadata = nb.metadata
compare(nb, nb2)
+
+
+def test_first_cell_markdown_191():
+ text = """# %% [markdown]
+# Docstring
+
+# %%
+from math import pi
+
+# %% [markdown]
+# Another markdown cell
+"""
+
+ nb = jupytext.reads(text, 'py')
+ assert nb.cells[0].cell_type == 'markdown'
+ assert nb.cells[1].cell_type == 'code'
+ assert nb.cells[2].cell_type == 'markdown'
diff --git a/tests/test_read_simple_scheme.py b/tests/test_read_simple_scheme.py
index dffa49625..ef532a530 100644
--- a/tests/test_read_simple_scheme.py
+++ b/tests/test_read_simple_scheme.py
@@ -13,15 +13,16 @@ def test_read_simple_file(script=""";; ---
(define a 35)
"""):
- nb = jupytext.reads(script, 'ss')
- assert len(nb.cells) == 3
- assert nb.cells[0].cell_type == 'raw'
- assert nb.cells[0].source == '---\ntitle: Simple file\n---'
- assert nb.cells[1].cell_type == 'markdown'
- assert nb.cells[1].source == 'Here we have some text\n' \
- 'And below we have some code'
- assert nb.cells[2].cell_type == 'code'
- compare(nb.cells[2].source, '(define a 35)')
+ for file_extension in ('ss', 'scm'):
+ nb = jupytext.reads(script, file_extension)
+ assert len(nb.cells) == 3
+ assert nb.cells[0].cell_type == 'raw'
+ assert nb.cells[0].source == '---\ntitle: Simple file\n---'
+ assert nb.cells[1].cell_type == 'markdown'
+ assert nb.cells[1].source == 'Here we have some text\n' \
+ 'And below we have some code'
+ assert nb.cells[2].cell_type == 'code'
+ compare(nb.cells[2].source, '(define a 35)')
- script2 = jupytext.writes(nb, 'ss')
- compare(script, script2)
+ script2 = jupytext.writes(nb, file_extension)
+ compare(script, script2)