From d392ca9d642053d54692c711601e4535ec236a8e Mon Sep 17 00:00:00 2001 From: Jack Schmidt <1107865+jackschmidt@users.noreply.github.com> Date: Sat, 30 Apr 2022 16:30:49 -0400 Subject: [PATCH 01/22] fixed missing SubCodeEngine for javascript's js Most other engines have a SubCodeEngine(langname, filesuffix) to allow shorter macros to be used (\py instead of \python). The documentation says the same is true for javascript, but \js did not work prior to this commit. --- pythontex/pythontex_engines.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pythontex/pythontex_engines.py b/pythontex/pythontex_engines.py index 6b00dbb..9b1cb38 100644 --- a/pythontex/pythontex_engines.py +++ b/pythontex/pythontex_engines.py @@ -1748,3 +1748,4 @@ def cleanup ['error', 'Error'], ['warning', 'Warning'], ':{number}') +SubCodeEngine('javascript', 'js') From 9287970e468eedae4abea677758d7ae490127557 Mon Sep 17 00:00:00 2001 From: Geoffrey Poore Date: Sun, 4 Feb 2024 23:07:00 -0600 Subject: [PATCH 02/22] added development status to README --- README.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.rst b/README.rst index 7be4cea..946f8ba 100644 --- a/README.rst +++ b/README.rst @@ -94,6 +94,29 @@ in any resulting publications. The best and most recent paper is in `2013 SciPy proceedings `_. +Development status +================== + +Starting in 2020, I have increasingly used Markdown and HTML instead of +PythonTeX and LaTeX when creating new teaching materials. I can no longer +make major time investments in open-source software that I do not use +frequently myself. PythonTeX v0.19 is under development. It will address +some minor bugs and incompatibilities that have developed with Python and +dependencies over the last few years. After v0.19, there should be occasional +releases to keep PythonTeX running, but no major changes or significant new +features are anticipated. + +I have been developing `Codebraid `_ since 2019, +partially to have a PythonTeX equivalent for Markdown but also in the hope +that it could eventually be integrated with LaTeX as a PythonTeX replacement. +I currently have a grant to develop +`minted `_ v3.0, and as part of this am +creating new software for passing data between LaTeX and Python. I cannot +make any guarantees, but I hope that this will eventually make it possible to +create a new LaTeX package based on Codebraid, with significant PythonTeX +compatibility. + + License ======= From a0ebc5ad959e7389cbcd6f6f74f0d356e46d1712 Mon Sep 17 00:00:00 2001 From: Ernst Reissner Date: Sun, 6 Apr 2025 17:54:55 +0200 Subject: [PATCH 03/22] Update depythontex3.py and pythontex3.py: turned literal strings signifying regular expressions into raw strings This is to avoid escaping. This is necessary starting from at least python 3.11 --- pythontex/depythontex3.py | 60 +++++++++++++++++++-------------------- pythontex/pythontex3.py | 4 +-- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/pythontex/depythontex3.py b/pythontex/depythontex3.py index e27abea..860b0bd 100644 --- a/pythontex/depythontex3.py +++ b/pythontex/depythontex3.py @@ -161,7 +161,7 @@ def replace_code_cmd(name, arglist, linenum, code_replacement, # Make sure the introduction of an environment where a command was # previously won't produce errors with following content; make sure # that any following content is on a separate line - if bool(match('[ \t]*\S', after)): + if bool(match(r'[ \t]*\S', after)): after = '\n' + after # Rather than duplicating much of replace_code_env(), just use it return replace_code_env(name, arglist, linenum, code_replacement, @@ -333,7 +333,7 @@ def replace_print_cmd(name, arglist, linenum, break print_replacement = r'\verb' + delim + print_replacement + delim elif print_replacement_mode == 'verbatim': - if bool(match('\s*?\n', after)): + if bool(match(r'\s*?\n', after)): # Usually, we would end the verbatim environment with a newline. # This is fine if there is content in `after` before the next # newline---in fact, it's desirable, because the verbatim package @@ -405,11 +405,11 @@ def replace_print_cmd(name, arglist, linenum, # the `\input` content. print_replacement = print_replacement.rstrip(' \t\n') after = sub(r'^\\unskip\s+', '', after) - elif bool(match('\S', after)): + elif bool(match(r'\S', after)): # If the next character is not whitespace, we can just leave # the `\n`, and it will yield a space. pass - elif bool(match('\s*$', after)): + elif bool(match(r'\s*$', after)): # If the rest of the current line, and the next line, are # whitespace, we will get the correct spacing without needing # `\space{}`. We could leave `\n`, but it would be @@ -421,14 +421,14 @@ def replace_print_cmd(name, arglist, linenum, # it's at the end of an environment, and thus is needed to # protect the following content print_replacement += '\\space{}' - after = sub('^\s+', '', after) + after = sub(r'^\s+', '', after) forced_double_space_list.append((name, linenum)) else: - if bool(match('\s+\S', after)): + if bool(match(r'\s+\S', after)): # If the following line starts with whitespace, replace it # with a newline, to protect in the event that the printed # content ended with an end-of-environment command - after = sub('^\s+', '\n', after) + after = sub(r'^\s+', '\n', after) # Issue warnings, if warranted # Warn about `\endinput` if (r'\endinput' in print_replacement and @@ -519,17 +519,17 @@ def replace_print_env(name, arglist, linenum, if delim not in print_replacement: break print_replacement = r'\verb' + delim + print_replacement + delim - if not bool(match('[ \t]+\S', after)): + if not bool(match(r'[ \t]+\S', after)): # If there is text on the same line as the end of the # environment, we're fine (this is unusual). Otherwise, # we need to toss the newline at the end of the environment # and gobble leading spaces. Leading spaces need to be # gobbled because previously they were at the beginning of a # line, where they would have been discarded. - if not bool(match('\s*$', after)): - after = sub('^\s*?\n\s*', '', after) + if not bool(match(r'\s*$', after)): + after = sub(r'^\s*?\n\s*', '', after) elif print_replacement_mode == 'verbatim': - if bool(match('\s*?\n', after)): + if bool(match(r'\s*?\n', after)): # Usually, we would end the verbatim environment with a newline. # This is fine if there is content in `after` before the next # newline---in fact, it's desirable, because the verbatim package @@ -570,15 +570,15 @@ def replace_print_env(name, arglist, linenum, # printed content. Later, we issue a warning in case it appears # anywhere else. print_replacement = print_replacement.rsplit(r'\endinput', 1)[0] - if not bool(match('[ \t]+\S', after)): + if not bool(match(r'[ \t]+\S', after)): # If there is text on the same line as the end of the # environment, we're fine (this is unusual). Otherwise, # we need to toss the newline at the end of the environment # and gobble leading spaces. Leading spaces need to be # gobbled because previously they were at the beginning of a # line, where they would have been discarded. - if not bool(match('\s*$', after)): - after = sub('^\s*?\n\s*', '', after) + if not bool(match(r'\s*$', after)): + after = sub(r'^\s*?\n\s*', '', after) elif (print_replacement.endswith('%\n') and not print_replacement.endswith('\\%\n') and not print_replacement.endswith('\\string%\n')): @@ -590,15 +590,15 @@ def replace_print_env(name, arglist, linenum, # warning if there is reason to think that a percent character # was active in the last line. print_replacement = print_replacement.rsplit(r'%', 1)[0] - if not bool(match('[ \t]+\S', after)): + if not bool(match(r'[ \t]+\S', after)): # If there is text on the same line as the end of the # environment, we're fine (this is unusual). Otherwise, # we need to toss the newline at the end of the environment # and gobble leading spaces. Leading spaces need to be # gobbled because previously they were at the beginning of a # line, where they would have been discarded. - if not bool(match('\s*$', after)): - after = sub('^\s*?\n\s*', '', after) + if not bool(match(r'\s*$', after)): + after = sub(r'^\s*?\n\s*', '', after) else: # By default, LaTeX strips newlines and adds a space at the end # of each line of content that is brought in by `\input`. This @@ -611,13 +611,13 @@ def replace_print_env(name, arglist, linenum, # `\unskip` print_replacement = print_replacement.rstrip(' \t\n') after = sub(r'^\s*\\unskip\s+', '', after) - elif bool(match('[ \t]+\S', after)): + elif bool(match(r'[ \t]+\S', after)): # If the next character after the end of the environment is # not whitespace (usually not allowed), we can just leave # the `\n` in printed content, and it will yield a space. # So we need do nothing. But if there is text on that line # we need `\space{}`. - after = sub('^\s+', '\\space', after) + after = sub(r'^\s+', '\\space', after) forced_double_space_list.append((name, linenum)) else: # If the line at the end of the environment is blank, @@ -1080,7 +1080,7 @@ def replace_print_env(name, arglist, linenum, else: if obeylines: # Take into account possible whitespace before arg - if bool(match('[ \t]*\[', after)): + if bool(match(r'[ \t]*\[', after)): after = after.split('[', 1)[1] while ']' not in after: texlinenum += 1 @@ -1094,11 +1094,11 @@ def replace_print_env(name, arglist, linenum, after = sub('^[ \t]*', '', after) else: # Allow peeking ahead a line for the argument - if bool(match('\s*$', after)) and after.count('\n') < 2: + if bool(match(r'\s*$', after)) and after.count('\n') < 2: texlinenum += 1 after += tex[texlinenum] # Take into account possible whitespace before arg - if bool(match('\s*\[', after)): + if bool(match(r'\s*\[', after)): after = after.split('[', 1)[1] while ']' not in after: texlinenum += 1 @@ -1108,11 +1108,11 @@ def replace_print_env(name, arglist, linenum, optarg = None # Account for eating whitespace afterward, if arg not found if argindex == len(depy_args) - 1: - if bool(match('\s*$', after)) and after.count('\n') < 2: + if bool(match(r'\s*$', after)) and after.count('\n') < 2: texlinenum += 1 after += tex[texlinenum] - if not bool(match('\s*$', after)): - after = sub('^\s*', '', after) + if not bool(match(r'\s*$', after)): + after = sub(r'^\s*', '', after) arglist.append(optarg) elif arg == 'm': # Account for possible line breaks or spaces before arg @@ -1121,7 +1121,7 @@ def replace_print_env(name, arglist, linenum, else: if obeylines: # Account for possible leading whitespace - if bool(match('[ \t\f\v]*\{', after)): + if bool(match(r'[ \t\f\v]*\{', after)): after = after.split('{', 1)[1] else: print('* DePythonTeX error:') @@ -1129,10 +1129,10 @@ def replace_print_env(name, arglist, linenum, sys.exit(1) else: # Peek ahead a line if needed - if bool(match('\s*$', after)) and after.count('\n') < 2: + if bool(match(r'\s*$', after)) and after.count('\n') < 2: texlinenum += 1 after += tex[texlinenum] - if bool(match('\s*\{', after)): + if bool(match(r'\s*\{', after)): after = after.split('{', 1)[1] else: print('* DePythonTeX error:') @@ -1338,7 +1338,7 @@ def replace_print_env(name, arglist, linenum, after = tex[texlinenum] break after = after.split(end_environment, 1)[1] - if bool(match('\s*\n', after)): + if bool(match(r'\s*\n', after)): # If the line following `after` is whitespace, it should # be stripped, since most environments throw away # anything after the end of the environment @@ -1389,7 +1389,7 @@ def replace_print_env(name, arglist, linenum, # Take care of graphicspath if args.graphicspath and settings['graphicx']: for n, line in enumerate(texout): - if '\\graphicspath' in line and not bool(match('\s*%', line)): + if '\\graphicspath' in line and not bool(match(r'\s*%', line)): texout[n] = line.replace('\\graphicspath{', '\\graphicspath{{' + settings['outputdir'] +'/}') break elif line.startswith(r'\begin{document}'): diff --git a/pythontex/pythontex3.py b/pythontex/pythontex3.py index 488c234..ea257cc 100644 --- a/pythontex/pythontex3.py +++ b/pythontex/pythontex3.py @@ -1807,7 +1807,7 @@ def run_code(encoding, outputdir, workingdir, # Get the gobbleation. This is used to determine if # other lines containing the basename are a continuation, # or separate messages. - errgobble = match('(\s*)', line).groups()[0] + errgobble = match(r'(\s*)', line).groups()[0] if start_errgobble is None: start_errgobble = errgobble # Only issue a message and track down the line numer if @@ -2072,7 +2072,7 @@ def run_code(encoding, outputdir, workingdir, # Get the gobbleation. This is used to determine if # other lines containing the basename are a continuation, # or separate messages. - errgobble = match('(\s*)', line).groups()[0] + errgobble = match(r'(\s*)', line).groups()[0] if start_errgobble is None: start_errgobble = errgobble # Only issue a message and track down the line numer if From 41b3e37b0b2e3ea717252ede10f33d3cf47f88cc Mon Sep 17 00:00:00 2001 From: Ernst Reissner Date: Sun, 6 Apr 2025 17:55:34 +0200 Subject: [PATCH 04/22] Update depythontex3.py and pythontex3.py: Escape backslash also this is necessary from python 3.11 on at least. --- pythontex/depythontex3.py | 4 ++-- pythontex/pythontex3.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pythontex/depythontex3.py b/pythontex/depythontex3.py index 860b0bd..4dd3576 100644 --- a/pythontex/depythontex3.py +++ b/pythontex/depythontex3.py @@ -121,7 +121,7 @@ def replace_code_cmd(name, arglist, linenum, code_replacement, Usually, code from a command is also typeset with a command. This function primarily deals with that case. In cases where code from a - command is typeset with an environment (for example, `\inputpygments`), + command is typeset with an environment (for example, `\\inputpygments`), this function performs some preprocessing and then uses replace_code_env() to do the real work. This approach prevents the two functions from unnecessarily duplicating each other, while still giving @@ -505,7 +505,7 @@ def replace_print_env(name, arglist, linenum, #### The inlineverb and verb modes should work, but haven't been tested since there are currently no environments that use them; they are only - used by `\printpythontex`, which is a command. + used by `\\printpythontex`, which is a command. ''' if print_replacement_mode == 'verb': if print_replacement.count('\n') > 1: diff --git a/pythontex/pythontex3.py b/pythontex/pythontex3.py index ea257cc..df5b647 100644 --- a/pythontex/pythontex3.py +++ b/pythontex/pythontex3.py @@ -554,7 +554,7 @@ def do_upgrade_compatibility(data, old_data, temp_data): It will continue to use the output directory for now. To keep your current settings long-term and avoid seeing this message in the future, add the following command to the preamble of your document, right after - the "\\usepackage{pythontex}": "\setpythontexworkingdir{}". + the "\\usepackage{pythontex}": "\\setpythontexworkingdir{}". If you wish to continue with the new settings instead, simply delete the file with extension .pkl in the output directory, and run PythonTeX. **** End PythonTeX upgrade message **** From 76218ed03090cd598fedfbe255ede65c27cca399 Mon Sep 17 00:00:00 2001 From: Geoffrey Poore Date: Tue, 28 Oct 2025 12:51:07 -0500 Subject: [PATCH 05/22] updated copyright and version --- pythontex/depythontex.py | 2 +- pythontex/depythontex2.py | 4 ++-- pythontex/depythontex3.py | 4 ++-- pythontex/pythontex.dtx | 6 +++--- pythontex/pythontex.ins | 4 ++-- pythontex/pythontex.py | 2 +- pythontex/pythontex.sty | 6 +++--- pythontex/pythontex2.py | 4 ++-- pythontex/pythontex3.py | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/pythontex/depythontex.py b/pythontex/depythontex.py index 3d48e3b..eb5feaf 100644 --- a/pythontex/depythontex.py +++ b/pythontex/depythontex.py @@ -9,7 +9,7 @@ launch depythontex2.py or depythontex3.py directly. The version of Python does not matter for depythontex, since no code is executed. -Copyright (c) 2013-2017, Geoffrey M. Poore +Copyright (c) 2013-2025, Geoffrey M. Poore All rights reserved. Licensed under the BSD 3-Clause License: http://www.opensource.org/licenses/BSD-3-Clause diff --git a/pythontex/depythontex2.py b/pythontex/depythontex2.py index 997a30d..c1387ed 100644 --- a/pythontex/depythontex2.py +++ b/pythontex/depythontex2.py @@ -47,7 +47,7 @@ typeset with a different package. -Copyright (c) 2013-2021, Geoffrey M. Poore +Copyright (c) 2013-2025, Geoffrey M. Poore All rights reserved. Licensed under the BSD 3-Clause License: http://www.opensource.org/licenses/BSD-3-Clause @@ -86,7 +86,7 @@ # Script parameters # Version -__version__ = '0.18' +__version__ = '0.19dev' # Functions and parameters for customizing the script output diff --git a/pythontex/depythontex3.py b/pythontex/depythontex3.py index 4dd3576..8e3b3e2 100644 --- a/pythontex/depythontex3.py +++ b/pythontex/depythontex3.py @@ -47,7 +47,7 @@ typeset with a different package. -Copyright (c) 2013-2021, Geoffrey M. Poore +Copyright (c) 2013-2025, Geoffrey M. Poore All rights reserved. Licensed under the BSD 3-Clause License: http://www.opensource.org/licenses/BSD-3-Clause @@ -86,7 +86,7 @@ # Script parameters # Version -__version__ = '0.18' +__version__ = '0.19dev' # Functions and parameters for customizing the script output diff --git a/pythontex/pythontex.dtx b/pythontex/pythontex.dtx index 38d44ff..eca01e6 100644 --- a/pythontex/pythontex.dtx +++ b/pythontex/pythontex.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -% Copyright (C) 2012-2021 by Geoffrey M. Poore +% Copyright (C) 2012-2025 by Geoffrey M. Poore % --------------------------------------------------------------------------- % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 @@ -26,7 +26,7 @@ %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{pythontex} %<*package> - [2021/06/06 v0.18 execute and typeset Python code and other languages] + [2025/10/28 v0.19dev execute and typeset Python code and other languages] % % %<*driver> @@ -1898,7 +1898,7 @@ % We store the name of the package in a macro for later use in warnings and error messages. % \begin{macrocode} \newcommand{\pytx@packagename}{PythonTeX} -\newcommand{\pytx@packageversion}{0.18} +\newcommand{\pytx@packageversion}{0.19dev} % \end{macrocode} % % \subsection{Required packages} diff --git a/pythontex/pythontex.ins b/pythontex/pythontex.ins index 83dd081..183c6c2 100644 --- a/pythontex/pythontex.ins +++ b/pythontex/pythontex.ins @@ -1,4 +1,4 @@ -%% Copyright (C) 2012-2019 by Geoffrey M. Poore +%% Copyright (C) 2012-2025 by Geoffrey M. Poore %% -------------------------------------------------------------------------- %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 @@ -25,7 +25,7 @@ This is a generated file. -Copyright (C) 2012-2021 by Geoffrey M. Poore +Copyright (C) 2012-2025 by Geoffrey M. Poore -------------------------------------------------------------------------- This work may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3 diff --git a/pythontex/pythontex.py b/pythontex/pythontex.py index 2fe6de9..56b38a7 100644 --- a/pythontex/pythontex.py +++ b/pythontex/pythontex.py @@ -16,7 +16,7 @@ Licensed under the BSD 3-Clause License: -Copyright (c) 2012-2017, Geoffrey M. Poore +Copyright (c) 2012-2025, Geoffrey M. Poore All rights reserved. diff --git a/pythontex/pythontex.sty b/pythontex/pythontex.sty index 5fa953f..630968e 100644 --- a/pythontex/pythontex.sty +++ b/pythontex/pythontex.sty @@ -8,7 +8,7 @@ %% %% This is a generated file. %% -%% Copyright (C) 2012-2021 by Geoffrey M. Poore +%% Copyright (C) 2012-2025 by Geoffrey M. Poore %% -------------------------------------------------------------------------- %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 @@ -20,10 +20,10 @@ %% \NeedsTeXFormat{LaTeX2e}[1999/12/01] \ProvidesPackage{pythontex} - [2021/06/06 v0.18 execute and typeset Python code and other languages] + [2025/10/28 v0.19dev execute and typeset Python code and other languages] \newcommand{\pytx@packagename}{PythonTeX} -\newcommand{\pytx@packageversion}{0.18} +\newcommand{\pytx@packageversion}{0.19dev} \RequirePackage{fvextra} \RequirePackage{etoolbox} \RequirePackage{xstring} diff --git a/pythontex/pythontex2.py b/pythontex/pythontex2.py index 661ef37..79dd82e 100644 --- a/pythontex/pythontex2.py +++ b/pythontex/pythontex2.py @@ -13,7 +13,7 @@ Licensed under the BSD 3-Clause License: -Copyright (c) 2012-2021, Geoffrey M. Poore +Copyright (c) 2012-2025, Geoffrey M. Poore All rights reserved. @@ -78,7 +78,7 @@ # Script parameters # Version -__version__ = '0.18' +__version__ = '0.19dev' diff --git a/pythontex/pythontex3.py b/pythontex/pythontex3.py index df5b647..c1f4ed1 100644 --- a/pythontex/pythontex3.py +++ b/pythontex/pythontex3.py @@ -13,7 +13,7 @@ Licensed under the BSD 3-Clause License: -Copyright (c) 2012-2021, Geoffrey M. Poore +Copyright (c) 2012-2025, Geoffrey M. Poore All rights reserved. @@ -78,7 +78,7 @@ # Script parameters # Version -__version__ = '0.18' +__version__ = '0.19dev' From 6a865de8c94e05eed65778438a5a468827ad8da4 Mon Sep 17 00:00:00 2001 From: Geoffrey Poore Date: Tue, 11 Nov 2025 10:24:34 -0600 Subject: [PATCH 06/22] fixed backslash escapes in docstrings for syntax compatibility with Python 3.11+ --- pythontex/depythontex3.py | 2 +- pythontex/pythontex_utils.py | 264 +++++++++++++++++------------------ 2 files changed, 133 insertions(+), 133 deletions(-) diff --git a/pythontex/depythontex3.py b/pythontex/depythontex3.py index 8e3b3e2..6adfe1d 100644 --- a/pythontex/depythontex3.py +++ b/pythontex/depythontex3.py @@ -29,7 +29,7 @@ facilitate customization. Most of the key substitutions are performed by a few functions defined near the beginning of the script, so if you need custom substitutions, you should begin there. By default, all typeset code is -wrapped in `\verb` commands and verbatim environments, since these have the +wrapped in `\\verb` commands and verbatim environments, since these have the greatest generality. However, the command-line option --listing allows code to be typeset with the fancyvrb, listings, minted, or PythonTeX packages instead. diff --git a/pythontex/pythontex_utils.py b/pythontex/pythontex_utils.py index 2731e7a..12bdd0b 100644 --- a/pythontex/pythontex_utils.py +++ b/pythontex/pythontex_utils.py @@ -2,11 +2,11 @@ ''' PythonTeX utilities class for Python scripts. -The utilities class provides variables and methods for the individual -Python scripts created and executed by PythonTeX. An instance of the class +The utilities class provides variables and methods for the individual +Python scripts created and executed by PythonTeX. An instance of the class named "pytex" is automatically created in each individual script. -Copyright (c) 2012-2014, Geoffrey M. Poore +Copyright (c) 2012-2025, Geoffrey M. Poore All rights reserved. Licensed under the BSD 3-Clause License: http://www.opensource.org/licenses/BSD-3-Clause @@ -20,27 +20,27 @@ if sys.version_info.major == 2: import io -# Most imports are only needed for SymPy; these are brought in via -# "lazy import." Importing unicode_literals here shouldn't ever be necessary -# under Python 2. If unicode_literals is imported in the main script, then -# all strings in this script will be treated as bytes, and the main script -# will try to decode the strings from this script as necessary. The decoding -# shouldn't cause any problems, since all strings in this file may be decoded -# as valid ASCII. (The actual file is encoded in utf-8, but only characters +# Most imports are only needed for SymPy; these are brought in via +# "lazy import." Importing unicode_literals here shouldn't ever be necessary +# under Python 2. If unicode_literals is imported in the main script, then +# all strings in this script will be treated as bytes, and the main script +# will try to decode the strings from this script as necessary. The decoding +# shouldn't cause any problems, since all strings in this file may be decoded +# as valid ASCII. (The actual file is encoded in utf-8, but only characters # within the ASCII subset are actually used). class PythonTeXUtils(object): ''' A class of PythonTeX utilities. - + Provides variables for keeping track of TeX-side information, and methods for formatting and saving data. - - The following variables and methods will be created within instances + + The following variables and methods will be created within instances of the class during execution. - - String variables for keeping track of TeX information. Most are + + String variables for keeping track of TeX information. Most are actually needed; the rest are included for completeness. * family * session @@ -50,21 +50,21 @@ class PythonTeXUtils(object): * args * instance * line - + Future file handle for output that is saved via macros * macrofile - + Future formatter function that is used to format output * formatter ''' - + def __init__(self, fmtr='str'): ''' Initialize ''' self.set_formatter(fmtr) - - # We need a function that will process the raw `context` into a + + # We need a function that will process the raw `context` into a # dictionary with attributes _context_raw = None class _DictWithAttr(dict): @@ -88,14 +88,14 @@ def set_context(self, expr): v = v[6:] self.context[k] = v setattr(self.context, k, v) - + # A primary use for contextual information is to pass dimensions from the # TeX side to the Python side. To make that as convenient as possible, # we need some length conversion functions. # Conversion reference: http://tex.stackexchange.com/questions/41370/what-are-the-possible-dimensions-sizes-units-latex-understands def pt_to_in(self, expr): ''' - Convert points to inches. Accepts numbers, strings of digits, and + Convert points to inches. Accepts numbers, strings of digits, and strings of digits that end with `pt`. ''' try: @@ -120,81 +120,81 @@ def pt_to_bp(self, expr): Convert points to big (DTP or PostScript) points. ''' return self.pt_to_in(expr)*72 - - - # We need a context-aware interface to SymPy's latex printer. The - # appearance of typeset math should depend on where it appears in a - # document. (We will refer to the latex printer, rather than the LaTeX - # printer, because the two are separate. Compare sympy.printing.latex - # and sympy.galgebra.latex_ex.) + + + # We need a context-aware interface to SymPy's latex printer. The + # appearance of typeset math should depend on where it appears in a + # document. (We will refer to the latex printer, rather than the LaTeX + # printer, because the two are separate. Compare sympy.printing.latex + # and sympy.galgebra.latex_ex.) # - # Creating this interface takes some work. We don't want to import - # anything from SymPy unless it is actually used, to keep things clean and + # Creating this interface takes some work. We don't want to import + # anything from SymPy unless it is actually used, to keep things clean and # fast. - - # First we create a tuple containing all LaTeX math styles. These are + + # First we create a tuple containing all LaTeX math styles. These are # the contexts that SymPy's latex printer must adapt to. # The style order doesn't matter, but it corresponds to that of \mathchoice _sympy_latex_styles = ('display', 'text', 'script', 'scriptscript') - - # Create the public functions for the user, and private functions that - # they call. Two layers are necessary, because we need to be able to - # redefine the functions that do the actual work, once things are - # initialized. But we don't want to redefine the public functions, since - # that could cause problems if the user defines a new function to be one + + # Create the public functions for the user, and private functions that + # they call. Two layers are necessary, because we need to be able to + # redefine the functions that do the actual work, once things are + # initialized. But we don't want to redefine the public functions, since + # that could cause problems if the user defines a new function to be one # of the public functions--the user's function would not change when # the method was redefined. def _sympy_latex(self, expr, **settings): self._init_sympy_latex() return self._sympy_latex(expr, **settings) - + def sympy_latex(self, expr, **settings): return self._sympy_latex(expr, **settings) - + def _set_sympy_latex(self, style, **kwargs): self._init_sympy_latex() self._set_sympy_latex(style, **kwargs) - + def set_sympy_latex(self, style, **kwargs): self._set_sympy_latex(style, **kwargs) # Temporary compatibility with deprecated methods def init_sympy_latex(self): warnings.warn('Method init_sympy_latex() is deprecated; init is now automatic.') self._init_sympy_latex() - - # Next we create a method that initializes the actual context-aware + + # Next we create a method that initializes the actual context-aware # interface to SymPy's latex printer. def _init_sympy_latex(self): ''' Initialize a context-aware interface to SymPy's latex printer. - - This consists of creating the dictionary of settings and creating the - sympy_latex method that serves as an interface to SymPy's - LatexPrinter. This last step is actually performed by calling + + This consists of creating the dictionary of settings and creating the + sympy_latex method that serves as an interface to SymPy's + LatexPrinter. This last step is actually performed by calling self._make_sympy_latex(). ''' # Create dictionaries of settings for different contexts. - # - # Currently, the main goal is to use pmatrix (or an equivalent) - # in \displaystyle contexts, and smallmatrix in \textstyle, + # + # Currently, the main goal is to use pmatrix (or an equivalent) + # in \displaystyle contexts, and smallmatrix in \textstyle, # \scriptstyle (superscript or subscript), and \scriptscriptstyle - # (superscript or subscript of a superscript or subscript) - # contexts. Basically, we want matrix size to automatically - # scale based on context. It is expected that additional - # customization may prove useful as SymPy's LatexPrinter is + # (superscript or subscript of a superscript or subscript) + # contexts. Basically, we want matrix size to automatically + # scale based on context. It is expected that additional + # customization may prove useful as SymPy's LatexPrinter is # further developed. # - # The 'fold_frac_powers' option is probably the main other - # setting that might sometimes be nice to invoke in a + # The 'fold_frac_powers' option is probably the main other + # setting that might sometimes be nice to invoke in a # context-dependent manner. # - # In the default settings below, all matrices are set to use - # parentheses rather than square brackets. This is largely a - # matter of personal preference. The use of parentheses is based - # on the rationale that parentheses are less easily confused with - # the determinant and are easier to write by hand than are square + # In the default settings below, all matrices are set to use + # parentheses rather than square brackets. This is largely a + # matter of personal preference. The use of parentheses is based + # on the rationale that parentheses are less easily confused with + # the determinant and are easier to write by hand than are square # brackets. The settings for 'script' and 'scriptscript' are set - # to those of 'text', since all of these should in general + # to those of 'text', since all of these should in general # require a more compact representation of things. self._sympy_latex_settings = {'display': {'mat_str': 'pmatrix', 'mat_delim': None}, 'text': {'mat_str': 'smallmatrix', 'mat_delim': '('}, @@ -202,13 +202,13 @@ def _init_sympy_latex(self): 'scriptscript': {'mat_str': 'smallmatrix', 'mat_delim': '('} } # Now we create a function for updating the settings. # - # Note that EVERY time the settings are changed, we must call - # self._make_sympy_latex(). This is because the _sympy_latex() - # method is defined based on the settings, and every time the - # settings change, it may need to be redefined. It would be - # possible to define _sympy_latex() so that its definition remained - # constant, simply drawing on the settings. But most common - # combinations of settings allow more efficient versions of + # Note that EVERY time the settings are changed, we must call + # self._make_sympy_latex(). This is because the _sympy_latex() + # method is defined based on the settings, and every time the + # settings change, it may need to be redefined. It would be + # possible to define _sympy_latex() so that its definition remained + # constant, simply drawing on the settings. But most common + # combinations of settings allow more efficient versions of # _sympy_latex() to be defined. def _set_sympy_latex(style, **kwargs): if style in self._sympy_latex_styles: @@ -220,79 +220,79 @@ def _set_sympy_latex(style, **kwargs): warnings.warn('Unknown LaTeX math style ' + str(style)) self._make_sympy_latex() self._set_sympy_latex = _set_sympy_latex - - # Now that the dictionaries of settings have been created, and - # the function for modifying the settings is in place, we are ready + + # Now that the dictionaries of settings have been created, and + # the function for modifying the settings is in place, we are ready # to create the actual interface. self._make_sympy_latex() - + # Finally, create the actual interface to SymPy's LatexPrinter def _make_sympy_latex(self): ''' Create a context-aware interface to SymPy's LatexPrinter class. - - This is an interface to the LatexPrinter class, rather than - to the latex function, because the function is simply a - wrapper for accessing the class and because settings may be + + This is an interface to the LatexPrinter class, rather than + to the latex function, because the function is simply a + wrapper for accessing the class and because settings may be passed to the class more easily. - - Context dependence is accomplished via LaTeX's \mathchoice macro. + + Context dependence is accomplished via LaTeX's \\mathchoice macro. This macros takes four arguments: - \mathchoice{}{}{