diff options
author | Norbert Preining <norbert@preining.info> | 2024-01-18 03:01:29 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2024-01-18 03:01:29 +0000 |
commit | c4dbe7c982d00abf62e9a8927ecdef11521773a8 (patch) | |
tree | 58b814095058ab06b7b49e3ef819293f1e0f9922 /macros/latex/contrib/pythonimmediate | |
parent | 4fd81a66c82a2ba8787c6ca78bfcc14820e4017c (diff) |
CTAN sync 202401180301
Diffstat (limited to 'macros/latex/contrib/pythonimmediate')
-rw-r--r-- | macros/latex/contrib/pythonimmediate/README | 2 | ||||
-rw-r--r-- | macros/latex/contrib/pythonimmediate/pythonimmediate.pdf | bin | 431593 -> 437287 bytes | |||
-rw-r--r-- | macros/latex/contrib/pythonimmediate/pythonimmediate.sty | 18 | ||||
-rw-r--r-- | macros/latex/contrib/pythonimmediate/pythonimmediate.tex | 51 | ||||
-rw-r--r-- | macros/latex/contrib/pythonimmediate/pythonimmediate_helper.lua | 131 |
5 files changed, 161 insertions, 41 deletions
diff --git a/macros/latex/contrib/pythonimmediate/README b/macros/latex/contrib/pythonimmediate/README index 43c413e62c..9a6d7b9e1a 100644 --- a/macros/latex/contrib/pythonimmediate/README +++ b/macros/latex/contrib/pythonimmediate/README @@ -7,7 +7,7 @@ Report bugs at https://github.com/user202729/pythonimmediate-tex ======== -Copyright 2022-2023 user202729 +Copyright 2022-2024 user202729 This work may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this license or diff --git a/macros/latex/contrib/pythonimmediate/pythonimmediate.pdf b/macros/latex/contrib/pythonimmediate/pythonimmediate.pdf Binary files differindex 5b8bf34442..cfcc852434 100644 --- a/macros/latex/contrib/pythonimmediate/pythonimmediate.pdf +++ b/macros/latex/contrib/pythonimmediate/pythonimmediate.pdf diff --git a/macros/latex/contrib/pythonimmediate/pythonimmediate.sty b/macros/latex/contrib/pythonimmediate/pythonimmediate.sty index 4556973831..1e632aba96 100644 --- a/macros/latex/contrib/pythonimmediate/pythonimmediate.sty +++ b/macros/latex/contrib/pythonimmediate/pythonimmediate.sty @@ -1,5 +1,5 @@ % File: pythonimmediate.sty -% Copyright 2022-2023 user202729 +% Copyright 2022-2024 user202729 % % This work may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this license or @@ -12,9 +12,10 @@ % % The Current Maintainer of this work is user202729. -\ProvidesExplPackage{pythonimmediate}{2023/03/07}{0.4.0}{Library to run Python code} +\ProvidesExplPackage{pythonimmediate}{2024/01/18}{0.5.0}{Library to run Python code} \RequirePackage{saveenv} +\PassOptionsToPackage{abspath}{currfile} % try to enable abspath if possible (i.e. if package isn't loaded) but otherwise don't give option-clash error \RequirePackage{currfile} \RequirePackage{l3keys2e} \RequirePackage{precattl} @@ -110,11 +111,14 @@ \bool_if:NTF \_pythonimmediate_child_process { \newwrite \_pythonimmediate_write_file - %\immediate\openout \_pythonimmediate_write_file=symlink-to-stderr.txt~ - % tried this method, it seems to work except that it's buffered when stderr is redirected to a file... - \immediate\openout \_pythonimmediate_write_file=|"\_pythonimmediate_python_executable \space \_pythonimmediate_python_flags \space -m ~ pythonimmediate.copy_to_stderr"~ - - + \sys_if_engine_luatex:TF { + % use Lua to write to stderr + \directlua{ (require "pythonimmediate_helper")() } + } { + %\immediate\openout \_pythonimmediate_write_file=symlink-to-stderr.txt~ + % tried this method, it seems to work except that it's buffered when stderr is redirected to a file... + \immediate\openout \_pythonimmediate_write_file=|"\_pythonimmediate_python_executable \space \_pythonimmediate_python_flags \space -m ~ pythonimmediate.copy_to_stderr"~ + } } { \sys_if_engine_luatex:TF { diff --git a/macros/latex/contrib/pythonimmediate/pythonimmediate.tex b/macros/latex/contrib/pythonimmediate/pythonimmediate.tex index 539a770fc2..9e6b0c1d8b 100644 --- a/macros/latex/contrib/pythonimmediate/pythonimmediate.tex +++ b/macros/latex/contrib/pythonimmediate/pythonimmediate.tex @@ -1,4 +1,4 @@ -\ProvidesFile{pythonimmediate.tex}[2023/03/07 0.4.0 Library to run Python code] +\ProvidesFile{pythonimmediate.tex}[2024/01/18 0.5.0 Library to run Python code] \RequirePackage{fvextra} \documentclass{l3doc} \usepackage{tikz} @@ -6,7 +6,8 @@ \usetikzlibrary{arrows.meta} \EnableCrossrefs \CodelineIndex -\fvset{breaklines=true,gobble=0,tabsize=4,frame=single,numbers=left,numbersep=3pt} +\fvset{breaklines=true,breakanywhere,gobble=0,tabsize=4,frame=single,numbers=left,numbersep=3pt} +\usepackage{cleveref} \AtBeginDocument{\DeleteShortVerb\"} % https://tex.stackexchange.com/a/650966/250119 \MakeOuterQuote{"} @@ -17,6 +18,7 @@ \begin{document} +\hfuzz=15pt % hack to make quotes inside |...| straight \edef\temp{\def\noexpand|{\noexpand\Verb\string|}}\temp @@ -53,7 +55,7 @@ In addition to the \LaTeX\ package, you need the Python \pkg{pythonimmediate-tex installation instruction can be found at \url{https://pypi.org/project/pythonimmediate-tex/}. Note that not all \TeX\ package versions are compatible with all Python package versions. -This \TeX\ package is compatible with Python package version |0.4.0|. +This \TeX\ package is compatible with Python package version |0.6.0|. Remember to enable unrestricted\footnote{ There's little point in supporting restricted mode, since it's possible to execute arbitrary shell commands in Python anyway. @@ -73,39 +75,43 @@ Instruction: \begin{itemize} \item Download the following files and place it in the root folder of Overleaf: \begin{itemize} - \item \file{saveenv.sty} - \item \file{precattl.sty} \item \file{pythonimmediate.sty} \item \file{pythonimmediate_helper.lua} - \item \file{pythonimmediate-tex-0.4.0.zip} + \item \file{pythonimmediate-tex-0.6.0.zip} \end{itemize} - The |0.4.0| part should be replaced with the desired version + The |0.6.0| part should be replaced with the desired version of the Python package. The |.sty| files can be downloaded from CTAN at - \url{https://ctan.org/pkg/saveenv}, - \url{https://ctan.org/pkg/precattl}, - \url{https://ctan.org/pkg/pythonimmediate} - respectively. + \url{https://ctan.org/pkg/pythonimmediate}. The |.zip| file containing Python source code can be downloaded from PyPI: \url{https://pypi.org/project/pythonimmediate-tex/\#files}. + Remark: Currently the \LaTeX\ package version 0.4.0 is included in \TeX\ Live 2023, you would need to download \LaTeX\ version 0.5.0 from CTAN. + + \item In older \TeX\ Live versions (2022 or less), you will in addition need to download the following files: + \begin{itemize} + \item \file{saveenv.sty} (from \url{https://ctan.org/pkg/saveenv}), + \item \file{precattl.sty} (from \url{https://ctan.org/pkg/precattl}). + \end{itemize} + Also place in the root folder of Overleaf. + \item Write the following in the preamble: \begin{verbatim} \usepackage[abspath]{currfile} -\usepackage[python-executable={PYTHONPATH=pythonimmediate-tex-0.4.0.zip/pythonimmediate-tex-0.4.0/ python3},args={--mode=unnamed-pipe}]{pythonimmediate} +\usepackage[python-executable={PYTHONPATH=pythonimmediate-tex-0.6.0.zip/pythonimmediate-tex-0.6.0/ python3},args={--mode=unnamed-pipe}]{pythonimmediate} \end{verbatim} -As above, replace both occurrences of |0.4.0| with the downloaded version specified in the zip file above. +As above, replace both occurrences of |0.6.0| with the downloaded version specified in the zip file above. -Refer to \ref{troubleshoot-source-file-not-found} for explanation of the |abspath| option. +Refer to \cref{troubleshoot-source-file-not-found} for explanation of the |abspath| option. \end{itemize} For some unknown reason in the default mode on Overleaf (|\nonstopmode|), when there's an error the log file might be truncated, so in that case consider writing |\errorstopmode|. -Refer to \ref{troubleshoot-Python-error} to read the error traceback in case of Python error. +Refer to \cref{troubleshoot-Python-error} to read the error traceback in case of Python error. Some construct inside the |pycode| block might make the code editor on Overleaf report an error, even though the code is valid. Refer to \url{https://www.overleaf.com/learn/how-to/Code_Check#Code_Check_Limitations}. @@ -131,7 +137,7 @@ The documentation is also available at The name/path to the Python executable. Default to |python3|. Can also be used to provide environment variables to the Python process. -An example how to do that is explained in \ref{installation-on-overleaf}. +An example how to do that is explained in \cref{installation-on-overleaf}. \DescribeOption{python-flags=} Flags to be passed to the Python interpreter. For example pass |-O| to disable assertions. @@ -202,7 +208,7 @@ Execute some Python code provided as an argument (the argument will be interpret The command is not expandable -- roughly speaking, you can only use this at "top level". -Any output (as described in \ref{print-to-TeX}) will be typesetted. +Any output (as described in \cref{print-to-TeX}) will be typesetted. The difference between |\py| and |\pyc| is that the argument of |\py| should be a Python expression (suitable for passing into |eval()| Python function) while the argument of |\pyc| should be a Python @@ -217,7 +223,7 @@ Therefore, \end{itemize} \DescribeMacro{\pycq} -Same as above, but output (\ref{print-to-TeX}) will not be typesetted. +Same as above, but output (\cref{print-to-TeX}) will not be typesetted. \DescribeMacro{\pyfile} Given an argument being the file name, execute that file. @@ -240,7 +246,7 @@ pythonimmediate.print("123") Special note: white spaces at the end of lines are preserved. -Any output (as described in \ref{print-to-TeX}) will be typesetted. +Any output (as described in \cref{print-to-TeX}) will be typesetted. \DescribeEnv{pycodeq} Same as above, but output will not be typesetted. @@ -366,7 +372,7 @@ $f(x)=1$, $f_i(x)=2$, $f_{ij}(x)=3$ \DescribePython{.get_arg_estr()} \DescribePython{.get_optional_arg_estr()} Similar to some functions above, except that the argument is fully expanded and "escapes" of common characters are handled correctly, -similar to how |\py| command (\ref{py-command}) reads its arguments. +similar to how |\py| command (\cref{py-command}) reads its arguments. \DescribePython{.execute()} Takes a string and execute it immediately. (so that any |.execute()| will be executed before any |.print_TeX()|) @@ -398,6 +404,11 @@ and as the second line throws an error, the Python traceback will point to that \section{Troubleshooting} +\subsection{"Incompatible TeX package version" error message}\label{troubleshoot-incompatible-version} +Exactly what it means. You can upgrade both the Python package and the TeX package to the latest version. + +Alternatively, you can also \emph{downgrade} whichever package that is newer. For instance, Python package version 0.5.0 (download from \url{https://pypi.org/project/pythonimmediate-tex/0.5.0/#files}) is compatible with \LaTeX\ package version 0.4.0. + \subsection{"Source file not found!" error message}\label{troubleshoot-source-file-not-found} In order to obtain the exact code with trailing spaces and produce error traceback diff --git a/macros/latex/contrib/pythonimmediate/pythonimmediate_helper.lua b/macros/latex/contrib/pythonimmediate/pythonimmediate_helper.lua index 8590233242..f5c54c1239 100644 --- a/macros/latex/contrib/pythonimmediate/pythonimmediate_helper.lua +++ b/macros/latex/contrib/pythonimmediate/pythonimmediate_helper.lua @@ -1,20 +1,125 @@ return function(cmd) - local process = io.popen(cmd, "w") + -- as mentioned in the .sty file this allows explicit flush after each write + -- it's not easy to eliminate having to spawn 2 Python processes even with Lua https://stackoverflow.com/questions/8716527/interactive-popen-lua-call + + + -- if this is a child process, should write to stderr, in which case cmd will be nil + local send_content + if cmd==nil then + send_content=function(str) + io.stderr:write(str.."\n") + io.stderr:flush() + end + else + process = io.popen(cmd, "w") + send_content=function(str) + process:write(str.."\n") + process:flush() + end + end local function_table=lua.get_functions_table() -- https://tex.stackexchange.com/questions/632408/how-can-i-exclude-tex-macros-when-counting-a-strings-characters-in-lua/632464?noredirect=1#comment1623008_632464 this only work in Lua 5.3 or assume it's allocated sequentially local send_content_index=#function_table+1 function_table[send_content_index]=function() - process:write(token.scan_string()) - process:write("\n") - process:flush() - end - - local close_index=#function_table+1 - function_table[close_index]=function() - process:close() - end - - tex.print([[\protected \luadef \_pythonimmediate_send_content:e ]] .. send_content_index .. [[\protected \luadef \_pythonimmediate_close_write: ]] .. close_index .. [[\relax]]) - end + send_content(token.scan_string()) + end + + local close_index=#function_table+1 + function_table[close_index]=function() + process:close() + end + + local bgroup=token.create(0x7b, 1) + local egroup=token.create(0x7d, 2) + + token.put_next( + bgroup, + token.create("ifodd"), + token.create(0x31, 12), + token.create("fi"), + egroup + ) + local frozen_relax_tok=token.scan_toks(false, true)[1].tok + local null_cs_tok=0x20000000 -- \csname\endcsname + + local cmdname_to_type={ + left_brace="1", + right_brace="2", + math_shift="3", + tab_mark ="4", + mac_param ="6", + sup_mark ="7", + sub_mark ="8", + spacer ="A", + letter ="B", + other_char="C", + } + local function serialize(tl) + local result={} + for _, v in ipairs(tl) do + local s -- serialized result of v + local function handle_character(cat, index, char) + if index<32 then + s="^"..cat..utf8.char(index+64) + else + s=cat..char + end + end + if v.csname~=nil then + if v.active then + handle_character("D", utf8.codepoint(v.csname), v.csname) + elseif v.tok==frozen_relax_tok then + s="R" + elseif v.tok==null_cs_tok then + s="\\ " + else + local c=v.csname + s="" + for i=1, #c do + if c:byte(i)<33 then s=s.."*" end + end + s="\\" + for i=1, #c do + if c:byte(i)<33 then + s=s.." "..string.char(c:byte(i)+64) + else + s=s..c:sub(i,i) + end + end + s=s.." " + end + else + assert(cmdname_to_type[v.cmdname]~=nil) + handle_character(cmdname_to_type[v.cmdname], v.mode, utf8.char(v.mode)) + end + result[#result+1]=s + end + return table.concat(result) + end + + local serialize_index=#function_table+1 + function_table[serialize_index]=function() + local result_token=token.get_next() + assert(result_token.csname~=nil and not result_token.active) + local tl=token.scan_toks() + --token.set_macro(-2, result_token.csname, table.concat(result)) + tex.sprint{token.create "def", result_token, bgroup} + tex.sprint(-2, serialize(tl)) + tex.sprint(egroup) + end + + local send_balanced_index=#function_table+1 + function_table[send_balanced_index]=function() + local tl=token.scan_toks() + send_content(serialize(tl)) + end + + tex.print( + [[\protected \luadef \_pythonimmediate_send_content:e ]] .. send_content_index .. + [[\protected \luadef \_pythonimmediate_close_write: ]] .. close_index .. + [[\protected \luadef \_pythonimmediate_tlserialize_nodot_unchecked:Nn ]] .. serialize_index .. + [[\protected \luadef \_pythonimmediate_send_balanced_tl:n ]] .. send_balanced_index .. + [[\relax]]) +end |