% Author : C. Pierquet % Thanks : F. Pantigny (for helping with piton/pyluatex) % licence : Released under the LaTeX Project Public License v1.3c or later, see http://www.latex-project.org/lppl.txtf \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{pynotebook}[2024/03/30 0.1.3 Present codes like in jupyter notebook] %0.1.3 Modification with gobble (piton) %0.1.2 Enhancement with gobble and new code for in/out with all numbers lines %0.1.1 New block In/Out %0.1.0 Initial version %------Usefull packages and libraries \RequirePackage{tcolorbox} \RequirePackage{iftex} \RequirePackage{xstring} \RequirePackage{calc} \tcbuselibrary{skins,breakable} %-----Option(s) for not loading piton and not creating environments \newif\if@piton \@pitontrue \DeclareOption{nopiton}{\@pitonfalse}% \DeclareOption*{} \ProcessOptions\relax %------Utils \newcommand\JupyterPromptIn{In~} \newcommand\JupyterPromptOut{Out} \NewDocumentCommand\promptjupyter{ s m m m m }{% \IfBooleanTF{#1}% {\makebox[0pt][r]{\texttt{\color{#3}#2[~~]:#5}}\vspace{-\baselineskip}}% {\makebox[0pt][r]{\texttt{\color{#3}#2[#4]:#5}}\vspace{-\baselineskip}}% } \newcounter{JupyterIn} \NewDocumentCommand\SetJupyterLng{ m }{% \IfStrEqCase{#1}{% {en}{\renewcommand\JupyterPromptIn{In~}\renewcommand\JupyterPromptOut{Out}}% {fr}{\renewcommand\JupyterPromptIn{Entrée}\renewcommand\JupyterPromptOut{Sortie}}% }% [\renewcommand\JupyterPromptIn{In~}\renewcommand\JupyterPromptOut{Out}]% } %-----Parskip \newlength{\JupyterParSkip} \setlength{\JupyterParSkip}{0.33\baselineskip} \NewDocumentCommand\SetJupyterParSkip{ m }{% \IfStrEq{#1}{default}% {\setlength{\JupyterParSkip}{0.33\baselineskip}}% {\setlength{\JupyterParSkip}{#1}}% } \tcbset{tcbjpuparskip/.style={before skip=\JupyterParSkip,after skip=\JupyterParSkip}} %------With listings (pdflatex or lualatex) \ifluatex \tcbuselibrary{listings} \lstdefinestyle{PLJupyter}{% language = python, inputencoding = utf8, basicstyle = \ttfamily\footnotesize, keywordstyle = \color{green!50!black}, keywordstyle = [2]\color{magenta}, commentstyle = \color{gray}\itshape, stringstyle = \color{red!75}, numberstyle = \scriptsize\ttfamily\color{gray}, aboveskip = 0pt, belowskip = 0pt, tabsize = 4, showstringspaces = false, columns = fullflexible, keepspaces = true, breaklines = true, breakatwhitespace = true } \else \tcbuselibrary{listingsutf8} \lstdefinestyle{PLJupyter}{% language = python, inputencoding = utf8/latin1, basicstyle = \ttfamily\footnotesize, keywordstyle = \color{green!50!black}, keywordstyle = [2]\color{magenta}, commentstyle = \color{gray}\itshape, stringstyle = \color{red!75}, numberstyle = \scriptsize\ttfamily\color{gray}, aboveskip = 0pt, belowskip = 0pt, tabsize = 4, showstringspaces = false, columns = fullflexible, keepspaces = true, breaklines = true, breakatwhitespace = true } \fi \newlength{\LargeurPromptJupyterIn} \newlength{\LargeurPromptJupyterOut} \newlength{\LargeurPromptJupyter} \newlength{\OffsetPromptJupyter} \setlength{\OffsetPromptJupyter}{9pt} \newlength{\LargeurNumbersJupyter} \newcommand\SetJupyterLengths{% \settowidth{\LargeurPromptJupyterIn}{\footnotesize\texttt{\JupyterPromptIn[10]:}}% \settowidth{\LargeurPromptJupyterOut}{\footnotesize\texttt{\JupyterPromptOut[10]:}}% \setlength{\LargeurPromptJupyter}{\maxof{\LargeurPromptJupyterIn}{\LargeurPromptJupyterOut}} \settowidth{\LargeurNumbersJupyter}{\scriptsize\texttt{00}}% } \NewDocumentEnvironment{NotebookIn}{ s O{} m }% {% \SetJupyterLengths% \addtolength{\LargeurNumbersJupyter}{0.5mm}% \noindent% \IfBooleanTF{#1}% {\tcbset{tcbjpuptitlein/.style={title=\promptjupyter*{\JupyterPromptIn}{red!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupyter}}}}}% {\refstepcounter{JupyterIn}\tcbset{tcbjpuptitlein/.style={title=\promptjupyter{\JupyterPromptIn\ifnum\value{JupyterIn}<10~\fi}{red!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupyter}}}}}% \tcblisting{% breakable,sharp corners=all,enhanced,size=small,width=#3,tcbjpuparskip,boxrule=0.5pt, colframe=gray,colback=lightgray!15, left skip=\LargeurPromptJupyter+\OffsetPromptJupyter-2mm, tcbjpuptitlein, fonttitle=\linespread{1}\footnotesize, attach title to upper, listing only, listing options={style=PLJupyter,xleftmargin=\LargeurNumbersJupyter,numbers=left,firstnumber=1,numbersep=2mm},% overlay={\begin{tcbclipinterior}\draw[line width=0.5pt,gray] ([xshift={\LargeurNumbersJupyter+1mm}]frame.south west)--([xshift={\LargeurNumbersJupyter+1mm}]frame.north west);\end{tcbclipinterior}},% #2 }% }% {% \endtcblisting% } \NewDocumentEnvironment{NotebookConsole}{ O{} m }% {% \SetJupyterLengths% \addtolength{\LargeurNumbersJupyter}{0.5mm}% \noindent% \tcblisting{% breakable,sharp corners=all,enhanced,size=small,width=#2,tcbjpuparskip,boxrule=0.5pt, colframe=lightgray!25,colback=white, left skip=\LargeurPromptJupyter+\OffsetPromptJupyter-2mm, attach title to upper, listing only, listing options={style=tcblatex,basicstyle=\ttfamily\footnotesize},% #1 }% }% {% \endtcblisting% }% \NewDocumentEnvironment{NotebookOut}{ s O{} m }% {% \SetJupyterLengths% \addtolength{\LargeurNumbersJupyter}{0.5mm}% \IfBooleanTF{#1}% {\tcbset{tcbjpuptitleout/.style={title=\promptjupyter*{\JupyterPromptOut}{blue!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupyter}}}}}% {\tcbset{tcbjpuptitleout/.style={title=\promptjupyter{\JupyterPromptOut\ifnum\value{JupyterIn}<10~\fi}{blue!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupyter}}}}}% \noindent% \tcblisting{% breakable,sharp corners=all,enhanced,size=small,width=#3,tcbjpuparskip,boxrule=0.5pt, colframe=lightgray!25,colback=white, left skip=\LargeurPromptJupyter+\OffsetPromptJupyter-2mm, tcbjpuptitleout, fonttitle=\linespread{1}\footnotesize, attach title to upper, listing only, listing options={style=tcblatex,basicstyle=\ttfamily\footnotesize},% #2 }% }% {% \endtcblisting% }% \NewDocumentEnvironment{NotebookRaw}{ O{} m }% {% \SetJupyterLengths% \addtolength{\LargeurNumbersJupyter}{0.5mm}% \noindent% \tcblisting{% breakable,sharp corners=all,enhanced,size=small,width=#2,tcbjpuparskip,boxrule=0.5pt, colframe=gray,colback=lightgray!15, left skip=\LargeurPromptJupyter+\OffsetPromptJupyter-2mm, attach title to upper, listing only, listing options={style=tcblatex,basicstyle=\ttfamily\footnotesize,numberstyle=\scriptsize\ttfamily\color{gray},xleftmargin=\LargeurNumbersJupyter,numbers=left,firstnumber=1,numbersep=2mm},% overlay={\begin{tcbclipinterior}\draw[line width=0.5pt,gray] ([xshift={\LargeurNumbersJupyter+1mm}]frame.south west)--([xshift={\LargeurNumbersJupyter+1mm}]frame.north west);\end{tcbclipinterior}},% #1 }% }% {% \endtcblisting% }% \NewDocumentEnvironment{NotebookMarkdown}{ O{} m }% {% \SetJupyterLengths% \addtolength{\LargeurNumbersJupyter}{0.5mm}% \noindent% \tcolorbox[breakable,sharp corners=all,enhanced,size=small,boxrule=0.5pt,width=#2,tcbjpuparskip,colframe=lightgray!25,colback=white,left skip=\LargeurPromptJupyter+\OffsetPromptJupyter-2mm, attach title to upper,fontupper=\footnotesize,tcbjpuparskip,#1]% }% {% \endtcolorbox% }% \if@piton %----With Piton (only lualatex) \ifluatex \RequirePackage{piton} %\RequirePackage{environ} \newlength{\LargeurPromptJupiter} \newlength{\LargeurPromptJupiterIn} \newlength{\LargeurPromptJupiterOut} \newlength{\OffsetPromptJupiter} \setlength{\OffsetPromptJupiter}{9pt} \newlength{\LargeurNumbersJupiter} \newcommand\SetJupiterLengths{% \settowidth{\LargeurPromptJupiterIn}{\footnotesize\texttt{\JupyterPromptIn[10]:}}% \settowidth{\LargeurPromptJupiterOut}{\footnotesize\texttt{\JupyterPromptOut[10]:}}% \setlength{\LargeurPromptJupiter}{\maxof{\LargeurPromptJupiterIn}{\LargeurPromptJupiterOut}}% \settowidth{\LargeurNumbersJupiter}{\footnotesize\texttt{00}}% } \NewPitonEnvironment{NotebookPitonIn}{ s O{} m !D<>{} }% {% \SetJupiterLengths% \IfBooleanTF{#1}% {\tcbset{tcbjpuptitlein/.style={title=\promptjupyter*{\JupyterPromptIn}{red!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupiter}}}}}% {\refstepcounter{JupyterIn}\tcbset{tcbjpuptitlein/.style={title=\promptjupyter{\JupyterPromptIn\ifnum\value{JupyterIn}<10~\fi}{red!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupiter}}}}}% \noindent% \PitonOptions{left-margin={\LargeurNumbersJupiter+1.75mm},line-numbers={skip-empty-lines=false,label-empty-lines=true}}% \PitonOptions{break-lines,indent-broken-lines,continuation-symbol={},#4}% %on crée la boîte \tcolorbox[size=small,breakable,sharp corners=all,boxrule=0.5pt,enhanced,width=#3,colframe=gray,colback=lightgray!15,left skip=\LargeurPromptJupiter+\OffsetPromptJupiter-2mm,tcbjpuptitlein,fonttitle=\linespread{1}\footnotesize,attach title to upper,fontupper=\footnotesize,overlay={% \begin{tcbclipinterior}\draw[line width=0.5pt,gray] ([xshift={\LargeurNumbersJupiter+2.25mm}]frame.south west)--([xshift={\LargeurNumbersJupiter+2.25mm}]frame.north west);\end{tcbclipinterior}},bottom=-0.5mm,top=0.5mm,tcbjpuparskip,#2]% }% {% \endtcolorbox% \ignorespacesafterend% } \NewDocumentEnvironment{NotebookPitonConsole}{ O{} m !D<>{} }% {% \SetJupiterLengths% \noindent% \PitonOptions{width={#2-5mm-\LargeurPromptJupiter-\OffsetPromptJupiter+2mm},break-lines,end-of-broken-line={},continuation-symbol={},#3}% %on crée la boîte \PyLTVerbatimEnv% \tcolorbox[breakable,sharp corners=all,enhanced,size=small,boxrule=0.5pt,width=#2,colframe=lightgray!25,colback=white,left skip=\LargeurPromptJupiter+\OffsetPromptJupiter-2mm,attach title to upper,fontupper=\footnotesize,bottom=-0.5mm,tcbjpuparskip,#1]% \begin{pythonq}% }% {% \end{pythonq}% \directlua{% tex.print("\\begin{Piton}") tex.print(pyluatex.get_last_output()) tex.print("\\end{Piton}") }% \endtcolorbox% \ignorespacesafterend% } \NewDocumentEnvironment{NotebookPitonOut}{ s O{} m !D<>{} }% {% \SetJupiterLengths% \IfBooleanTF{#1}% {\tcbset{tcbjpuptitleout/.style={title=\promptjupyter*{\JupyterPromptOut}{blue!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupiter}}}}}% {\tcbset{tcbjpuptitleout/.style={title=\promptjupyter{\JupyterPromptOut\ifnum\value{JupyterIn}<10~\fi}{blue!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupiter}}}}}% \noindent% \PitonOptions{continuation-symbol={},end-of-broken-line={},break-lines,#4}% %on crée la boîte \PyLTVerbatimEnv% \tcolorbox[breakable,sharp corners=all,enhanced,size=small,boxrule=0.5pt,width=#3,colframe=lightgray!25,colback=white,left skip=\LargeurPromptJupiter+\OffsetPromptJupiter-2mm,tcbjpuptitleout,fonttitle=\linespread{1}\footnotesize,attach title to upper,fontupper=\footnotesize,bottom=-0.5mm,top=0.5mm,tcbjpuparskip,#2]% \begin{pythonq}% }% {% \end{pythonq}% \directlua{% tex.print("\\begin{Piton}") tex.print(pyluatex.get_last_output()) tex.print("\\end{Piton}") }% \endtcolorbox% \ignorespacesafterend% } \NewPitonEnvironment{NotebookPitonRaw}{ O{} m !D<>{} }% {% \SetJupiterLengths% \noindent% \SetPitonStyle{Number=}% \PitonOptions{left-margin={\LargeurNumbersJupiter+1.75mm},line-numbers={skip-empty-lines=false,label-empty-lines=true},language=minimal}% \PitonOptions{continuation-symbol={},break-lines,indent-broken-lines,#3}% %on crée la boîte \tcolorbox[breakable,sharp corners=all,enhanced,size=small,boxrule=0.5pt,width=#2,colframe=gray,colback=lightgray!25,left skip=\LargeurPromptJupiter+\OffsetPromptJupiter-2mm,attach title to upper,fontupper=\footnotesize,overlay={% \begin{tcbclipinterior}\draw[line width=0.5pt,gray] ([xshift={\LargeurNumbersJupiter+2.25mm}]frame.south west)--([xshift={\LargeurNumbersJupiter+2.25mm}]frame.north west);\end{tcbclipinterior}},bottom=-0.5mm,tcbjpuparskip,#1]% }% {% \endtcolorbox% \ignorespacesafterend% } \NewDocumentEnvironment{NotebookPitonMarkdown}{ O{} m }% {% \SetJupiterLengths% \noindent% \tcolorbox[breakable,sharp corners=all,enhanced,size=small,boxrule=0.5pt,width=#2,tcbjpuparskip,colframe=lightgray!25,colback=white,left skip=\LargeurPromptJupiter+\OffsetPromptJupiter-2mm, attach title to upper,fontupper=\footnotesize,tcbjpuparskip,#1]% }% {% \endtcolorbox% \ignorespacesafterend% }% \NewDocumentEnvironment{NotebookPitonInOut}{ s O{} m !D<>{} }% {% \PyLTVerbatimEnv% \begin{pythonq}% }% {% \end{pythonq}% \SetJupiterLengths% \IfBooleanTF{#1}% {% \tcbset{tcbjpuptitlein/.style={title=\promptjupyter*{\JupyterPromptIn}{red!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupiter}}}}% }% {% \refstepcounter{JupyterIn}% \tcbset{tcbjpuptitlein/.style={title=\promptjupyter{\JupyterPromptIn\ifnum\value{JupyterIn}<10~\fi}{red!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupiter}}}}% }% \noindent% \tcolorbox[breakable,sharp corners=all,enhanced,size=small,boxrule=0.5pt,width=#3,colframe=gray,colback=lightgray!15,left skip=\LargeurPromptJupiter+\OffsetPromptJupiter-2mm,tcbjpuptitlein,fonttitle=\linespread{1}\footnotesize, attach title to upper,fontupper=\footnotesize,overlay={\begin{tcbclipinterior}\draw[line width=0.5pt,gray] ([xshift={\LargeurNumbersJupiter+2.25mm}]frame.south west)--([xshift={\LargeurNumbersJupiter+2.25mm}]frame.north west) ;\end{tcbclipinterior}},bottom=-0.5mm,top=0.5mm,tcbjpuparskip,#2]% %\PitonOptions{width={#3-5mm}} \directlua{% tex.print("\\begin{Piton}[left-margin=\\LargeurNumbersJupiter+1.75mm,line-numbers={skip-empty-lines=false,label-empty-lines=true},break-lines,indent-broken-lines,continuation-symbol={},#4]") tex.print(pyluatex.get_last_code()) tex.print("\\end{Piton}") }% \endtcolorbox% \IfBooleanTF{#1}% {% \tcbset{tcbjpuptitleout/.style={title=\promptjupyter*{\JupyterPromptOut}{blue!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupiter}}}}% }% {% \tcbset{tcbjpuptitleout/.style={title=\promptjupyter{\JupyterPromptOut\ifnum\value{JupyterIn}<10~\fi}{blue!75!black}{\theJupyterIn}{\hspace*{\OffsetPromptJupiter}}}}% }% \tcbset{reset}% \noindent% \tcolorbox[breakable,sharp corners = all,enhanced,size=small,boxrule=0.5pt,width=#3,colframe=lightgray!25,colback=white,left skip=\LargeurPromptJupiter+\OffsetPromptJupiter-2mm,tcbjpuptitleout,fonttitle=\linespread{1}\footnotesize,attach title to upper,fontupper=\footnotesize,bottom=-0.5mm,top=0.5mm,tcbjpuparskip,#2]% %\PitonOptions{width={#3-5mm-\LargeurPromptJupiter-\OffsetPromptJupiter+2mm}} \directlua{% tex.print("\\begin{Piton}[break-lines,continuation-symbol={},end-of-broken-line={},#4]") tex.print(pyluatex.get_last_output()) tex.print("\\end{Piton}") }% \endtcolorbox% \ignorespacesafterend% } \NewPitonEnvironment{NotebookPitonAllNum}{ s O{} m !D<>{} }% {% \SetJupiterLengths \IfBooleanTF{#1}% {\tcbset { tcbjpuptitlein/.style = { title = \promptjupyter*{\JupyterPromptIn} {red!75!black} {\theJupyterIn} {\hspace*{\OffsetPromptJupiter}} }% }% }% {\refstepcounter{JupyterIn} \tcbset { tcbjpuptitlein/.style = { title = \promptjupyter{\JupyterPromptIn \ifnum\value{JupyterIn}<10~\fi} {red!75!black} {\theJupyterIn} {\hspace*{\OffsetPromptJupiter}} } }% }% \noindent \PitonOptions { left-margin = \LargeurNumbersJupiter + 1.75mm , all-line-numbers, break-lines, indent-broken-lines, continuation-symbol={}, #4 }% \tcolorbox[breakable, sharp corners=all, enhanced, size = small, boxrule = 0.5pt, width = #3, colframe = gray, colback = lightgray!15, left skip = \LargeurPromptJupiter+\OffsetPromptJupiter-2mm, tcbjpuptitlein, fonttitle = \linespread{1}\footnotesize, attach title to upper, fontupper = \footnotesize, overlay = {% \begin{tcbclipinterior} \draw[line width=0.5pt,gray] ([xshift={\LargeurNumbersJupiter+2.25mm}]frame.south west) --([xshift={\LargeurNumbersJupiter+2.25mm}]frame.north west) ; \end{tcbclipinterior}}, bottom = -0.5mm, tcbjpuparskip, #2]% } { \endtcolorbox % \tcbset{reset}% \IfBooleanTF{#1}% { \tcbset { tcbjpuptitleout/.style = { title = \promptjupyter*{\JupyterPromptOut} {blue!75!black} {\theJupyterIn} {\hspace*{\OffsetPromptJupiter}} } }% }% { \tcbset { tcbjpuptitleout/.style = { title = \promptjupyter{\JupyterPromptOut \ifnum\value{JupyterIn}<10~\fi} {blue!75!black} {\theJupyterIn} {\hspace*{\OffsetPromptJupiter}} } }% }% \tcolorbox[breakable, sharp corners = all, enhanced, size = small, boxrule = 0.5pt, width = #3, colframe = lightgray!25, colback = white, left skip = \LargeurPromptJupiter + \OffsetPromptJupiter - 2mm, tcbjpuptitleout, fonttitle = \linespread{1}\footnotesize, attach title to upper, fontupper = \footnotesize, overlay = {% \begin{tcbclipinterior} \draw[line width=0.5pt,lightgray!15] ([xshift={\LargeurNumbersJupiter+2.25mm}]frame.south west) --([xshift={\LargeurNumbersJupiter+2.25mm}]frame.north west) ; \end{tcbclipinterior}}, bottom = -0.5mm, tcbjpuparskip, #2]% \directlua{% tex.print("\\begin{Piton}") tex.print(pyluatex.execute(piton.get_last_code(), false, true, false, true)) tex.print("\\end{Piton}") }% \endtcolorbox% } \fi \fi \endinput