summaryrefslogtreecommitdiff
path: root/Master/texmf-dist
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist')
-rw-r--r--Master/texmf-dist/doc/latex/pythontex/NEWS.rst20
-rw-r--r--Master/texmf-dist/doc/latex/pythontex/README2
-rw-r--r--Master/texmf-dist/doc/latex/pythontex/pythontex.pdfbin975950 -> 979067 bytes
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/depythontex2.py4
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/depythontex3.py4
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/pythontex2.py33
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/pythontex3.py33
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/pythontex_engines.py8
-rw-r--r--Master/texmf-dist/source/latex/pythontex/pythontex.dtx23
-rw-r--r--Master/texmf-dist/source/latex/pythontex/pythontex.ins2
-rw-r--r--Master/texmf-dist/tex/latex/pythontex/pythontex.sty6
11 files changed, 101 insertions, 34 deletions
diff --git a/Master/texmf-dist/doc/latex/pythontex/NEWS.rst b/Master/texmf-dist/doc/latex/pythontex/NEWS.rst
index b0eccb7df58..69b60dad66a 100644
--- a/Master/texmf-dist/doc/latex/pythontex/NEWS.rst
+++ b/Master/texmf-dist/doc/latex/pythontex/NEWS.rst
@@ -7,6 +7,26 @@ Version History
===============
+v0.18 (2021/06/06)
+------------------
+
+* ``\inputpygments`` now checks inputted files for modification, so that
+ typeset code will correctly update when the source is changed (#162).
+
+* Julia now uses project flag "``--project=@.``" (#157, #158).
+
+* Fixed bug in processing Pygments options (``pygopt``) when a key is used
+ without a value (#181).
+
+* Some error handling for Windows was incompatible with other operating
+ systems: replaced checks for ``WindowsError`` with checks for ``OSError``
+ (#177).
+
+* Rust support is now compatible with document and working directory paths
+ that contain spaces (#167).
+
+
+
v0.17 (2019/09/22)
------------------
diff --git a/Master/texmf-dist/doc/latex/pythontex/README b/Master/texmf-dist/doc/latex/pythontex/README
index 3994eca34c9..8928d3d7489 100644
--- a/Master/texmf-dist/doc/latex/pythontex/README
+++ b/Master/texmf-dist/doc/latex/pythontex/README
@@ -3,7 +3,7 @@
===================================================================
:Author: Geoffrey Poore
-:Version: 0.17 (2019/09/22)
+:Version: 0.18 (2021/06/06)
:License: LPPL v1.3 or later (LaTeX code) and BSD 3-Clause (Python code)
:Development: https://github.com/gpoore/pythontex
:Requirements: Python 2.7 or 3.2+; Pygments
diff --git a/Master/texmf-dist/doc/latex/pythontex/pythontex.pdf b/Master/texmf-dist/doc/latex/pythontex/pythontex.pdf
index ad9183d3acd..f6cd05d9228 100644
--- a/Master/texmf-dist/doc/latex/pythontex/pythontex.pdf
+++ b/Master/texmf-dist/doc/latex/pythontex/pythontex.pdf
Binary files differ
diff --git a/Master/texmf-dist/scripts/pythontex/depythontex2.py b/Master/texmf-dist/scripts/pythontex/depythontex2.py
index f49fd229778..997a30d6eac 100755
--- a/Master/texmf-dist/scripts/pythontex/depythontex2.py
+++ b/Master/texmf-dist/scripts/pythontex/depythontex2.py
@@ -47,7 +47,7 @@ example, typeset code may have a different appearance or layout when it is
typeset with a different package.
-Copyright (c) 2013-2017, Geoffrey M. Poore
+Copyright (c) 2013-2021, 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 @@ import codecs
# Script parameters
# Version
-__version__ = '0.17'
+__version__ = '0.18'
# Functions and parameters for customizing the script output
diff --git a/Master/texmf-dist/scripts/pythontex/depythontex3.py b/Master/texmf-dist/scripts/pythontex/depythontex3.py
index 2d86edb5914..e27abea1188 100755
--- a/Master/texmf-dist/scripts/pythontex/depythontex3.py
+++ b/Master/texmf-dist/scripts/pythontex/depythontex3.py
@@ -47,7 +47,7 @@ example, typeset code may have a different appearance or layout when it is
typeset with a different package.
-Copyright (c) 2013-2017, Geoffrey M. Poore
+Copyright (c) 2013-2021, 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 @@ import codecs
# Script parameters
# Version
-__version__ = '0.17'
+__version__ = '0.18'
# Functions and parameters for customizing the script output
diff --git a/Master/texmf-dist/scripts/pythontex/pythontex2.py b/Master/texmf-dist/scripts/pythontex/pythontex2.py
index 34e151f4177..661ef37f2f4 100755
--- a/Master/texmf-dist/scripts/pythontex/pythontex2.py
+++ b/Master/texmf-dist/scripts/pythontex/pythontex2.py
@@ -13,7 +13,7 @@ should be in the same directory.
Licensed under the BSD 3-Clause License:
-Copyright (c) 2012-2019, Geoffrey M. Poore
+Copyright (c) 2012-2021, Geoffrey M. Poore
All rights reserved.
@@ -78,7 +78,7 @@ else:
# Script parameters
# Version
-__version__ = '0.17'
+__version__ = '0.18'
@@ -437,7 +437,7 @@ def load_code_get_settings(data, temp_data):
elif v in ('false', 'False'):
v = False
else:
- k = option
+ k = options
v = True
opt_dict[k] = v
if family != ':GLOBAL':
@@ -869,12 +869,15 @@ def hash_all(data, temp_data, old_data, engine_dict):
if family in pygments_settings:
if (not pygments_settings_changed[family] and
key in old_typeset_hash_dict and
- typeset_hash_dict[key] == old_typeset_hash_dict[key]):
+ typeset_hash_dict[key] == old_typeset_hash_dict[key] and
+ not modified_dependencies(key, data, old_data, temp_data)):
pygments_update[key] = False
if key in old_pygments_macros:
pygments_macros[key] = old_pygments_macros[key]
if key in old_pygments_files:
pygments_files[key] = old_pygments_files[key]
+ if key in old_dependencies:
+ dependencies[key] = old_dependencies[key]
else:
pygments_update[key] = True
else:
@@ -1229,7 +1232,7 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
exec_cmd = shlex.split(command.format(file=script.replace('\\', '\\\\'), File=script_full.replace('\\', '\\\\')))
try:
proc = subprocess.Popen(exec_cmd)
- except (WindowsError, FileNotFoundError) as e:
+ except (OSError, FileNotFoundError) as e:
if platform.system() == 'Windows' and e.errno == 2:
# Batch files won't be found when called without extension. They
# would be found if `shell=True`, but then getting the right
@@ -1359,11 +1362,15 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
# Add a Pygments process
if pygments_list:
+ # Uncomment the following for debugging
+ # do_pygments(encoding, outputdir, fvextfile, pygments_list,
+ # pygments_settings, typeset_cache, hashdependencies)
tasks.append(pool.apply_async(do_pygments, [encoding, outputdir,
fvextfile,
pygments_list,
pygments_settings,
- typeset_cache]))
+ typeset_cache,
+ hashdependencies]))
if verbose:
print(' - Pygments process')
@@ -1412,6 +1419,8 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
if result['pygments_files'][k]:
new_files = True
break
+ for k, v in result['dependencies'].items():
+ dependencies[k] = v
pygments_macros.update(result['pygments_macros'])
errors += result['errors']
warnings += result['warnings']
@@ -1560,7 +1569,7 @@ def run_code(encoding, outputdir, workingdir,
proc = subprocess.Popen(exec_cmd, stdout=out_file, stderr=err_file)
else:
proc = subprocess.Popen(exec_cmd, stdout=out_file, stderr=subprocess.STDOUT)
- except WindowsError as e:
+ except OSError as e:
if e.errno == 2:
# Batch files won't be found when called without extension. They
# would be found if `shell=True`, but then getting the right
@@ -2362,7 +2371,7 @@ def run_code(encoding, outputdir, workingdir,
def do_pygments(encoding, outputdir, fvextfile, pygments_list,
- pygments_settings, typeset_cache):
+ pygments_settings, typeset_cache, hashdependencies):
'''
Create Pygments content.
@@ -2380,6 +2389,7 @@ def do_pygments(encoding, outputdir, fvextfile, pygments_list,
warnings = 0
messages = []
messages.append('\n---- Messages for Pygments ----')
+ dependencies = {}
# Create dicts of formatters and lexers.
formatter = dict()
@@ -2402,6 +2412,12 @@ def do_pygments(encoding, outputdir, fvextfile, pygments_list,
f = open(c.extfile, encoding=encoding)
content = f.read()
f.close()
+ if hashdependencies:
+ hasher = sha1()
+ hasher.update(content.encode(encoding))
+ dependencies[c.key_typeset] = {c.extfile: (os.path.getmtime(c.extfile), hasher.hexdigest())}
+ else:
+ dependencies[c.key_typeset] = {c.extfile: (os.path.getmtime(c.extfile), '')}
else:
content = None
messages.append('* PythonTeX error')
@@ -2440,6 +2456,7 @@ def do_pygments(encoding, outputdir, fvextfile, pygments_list,
return {'process': 'pygments',
'pygments_files': pygments_files,
'pygments_macros': pygments_macros,
+ 'dependencies': dependencies,
'errors': errors,
'warnings': warnings,
'messages': messages}
diff --git a/Master/texmf-dist/scripts/pythontex/pythontex3.py b/Master/texmf-dist/scripts/pythontex/pythontex3.py
index bc61f912ca6..488c234c254 100755
--- a/Master/texmf-dist/scripts/pythontex/pythontex3.py
+++ b/Master/texmf-dist/scripts/pythontex/pythontex3.py
@@ -13,7 +13,7 @@ should be in the same directory.
Licensed under the BSD 3-Clause License:
-Copyright (c) 2012-2019, Geoffrey M. Poore
+Copyright (c) 2012-2021, Geoffrey M. Poore
All rights reserved.
@@ -78,7 +78,7 @@ else:
# Script parameters
# Version
-__version__ = '0.17'
+__version__ = '0.18'
@@ -437,7 +437,7 @@ def load_code_get_settings(data, temp_data):
elif v in ('false', 'False'):
v = False
else:
- k = option
+ k = options
v = True
opt_dict[k] = v
if family != ':GLOBAL':
@@ -869,12 +869,15 @@ def hash_all(data, temp_data, old_data, engine_dict):
if family in pygments_settings:
if (not pygments_settings_changed[family] and
key in old_typeset_hash_dict and
- typeset_hash_dict[key] == old_typeset_hash_dict[key]):
+ typeset_hash_dict[key] == old_typeset_hash_dict[key] and
+ not modified_dependencies(key, data, old_data, temp_data)):
pygments_update[key] = False
if key in old_pygments_macros:
pygments_macros[key] = old_pygments_macros[key]
if key in old_pygments_files:
pygments_files[key] = old_pygments_files[key]
+ if key in old_dependencies:
+ dependencies[key] = old_dependencies[key]
else:
pygments_update[key] = True
else:
@@ -1229,7 +1232,7 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
exec_cmd = shlex.split(command.format(file=script.replace('\\', '\\\\'), File=script_full.replace('\\', '\\\\')))
try:
proc = subprocess.Popen(exec_cmd)
- except (WindowsError, FileNotFoundError) as e:
+ except (OSError, FileNotFoundError) as e:
if platform.system() == 'Windows' and e.errno == 2:
# Batch files won't be found when called without extension. They
# would be found if `shell=True`, but then getting the right
@@ -1359,11 +1362,15 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
# Add a Pygments process
if pygments_list:
+ # Uncomment the following for debugging
+ # do_pygments(encoding, outputdir, fvextfile, pygments_list,
+ # pygments_settings, typeset_cache, hashdependencies)
tasks.append(pool.apply_async(do_pygments, [encoding, outputdir,
fvextfile,
pygments_list,
pygments_settings,
- typeset_cache]))
+ typeset_cache,
+ hashdependencies]))
if verbose:
print(' - Pygments process')
@@ -1412,6 +1419,8 @@ def do_multiprocessing(data, temp_data, old_data, engine_dict):
if result['pygments_files'][k]:
new_files = True
break
+ for k, v in result['dependencies'].items():
+ dependencies[k] = v
pygments_macros.update(result['pygments_macros'])
errors += result['errors']
warnings += result['warnings']
@@ -1560,7 +1569,7 @@ def run_code(encoding, outputdir, workingdir,
proc = subprocess.Popen(exec_cmd, stdout=out_file, stderr=err_file)
else:
proc = subprocess.Popen(exec_cmd, stdout=out_file, stderr=subprocess.STDOUT)
- except WindowsError as e:
+ except OSError as e:
if e.errno == 2:
# Batch files won't be found when called without extension. They
# would be found if `shell=True`, but then getting the right
@@ -2362,7 +2371,7 @@ def run_code(encoding, outputdir, workingdir,
def do_pygments(encoding, outputdir, fvextfile, pygments_list,
- pygments_settings, typeset_cache):
+ pygments_settings, typeset_cache, hashdependencies):
'''
Create Pygments content.
@@ -2380,6 +2389,7 @@ def do_pygments(encoding, outputdir, fvextfile, pygments_list,
warnings = 0
messages = []
messages.append('\n---- Messages for Pygments ----')
+ dependencies = {}
# Create dicts of formatters and lexers.
formatter = dict()
@@ -2402,6 +2412,12 @@ def do_pygments(encoding, outputdir, fvextfile, pygments_list,
f = open(c.extfile, encoding=encoding)
content = f.read()
f.close()
+ if hashdependencies:
+ hasher = sha1()
+ hasher.update(content.encode(encoding))
+ dependencies[c.key_typeset] = {c.extfile: (os.path.getmtime(c.extfile), hasher.hexdigest())}
+ else:
+ dependencies[c.key_typeset] = {c.extfile: (os.path.getmtime(c.extfile), '')}
else:
content = None
messages.append('* PythonTeX error')
@@ -2440,6 +2456,7 @@ def do_pygments(encoding, outputdir, fvextfile, pygments_list,
return {'process': 'pygments',
'pygments_files': pygments_files,
'pygments_macros': pygments_macros,
+ 'dependencies': dependencies,
'errors': errors,
'warnings': warnings,
'messages': messages}
diff --git a/Master/texmf-dist/scripts/pythontex/pythontex_engines.py b/Master/texmf-dist/scripts/pythontex/pythontex_engines.py
index 4928826bf1c..6b00dbbf6f5 100755
--- a/Master/texmf-dist/scripts/pythontex/pythontex_engines.py
+++ b/Master/texmf-dist/scripts/pythontex/pythontex_engines.py
@@ -17,7 +17,7 @@ document (script for execution).
-Copyright (c) 2012-2018, Geoffrey M. Poore
+Copyright (c) 2012-2021, Geoffrey M. Poore
All rights reserved.
Licensed under the BSD 3-Clause License:
http://www.opensource.org/licenses/BSD-3-Clause
@@ -1107,14 +1107,14 @@ julia_wrapper = '''
julia_sub = '''println("{field_delim}")\nprintln({field})\n'''
-CodeEngine('julia', 'julia', '.jl', '{julia} "{file}.jl"', julia_template,
+CodeEngine('julia', 'julia', '.jl', '{julia} --project=@. "{file}.jl"', julia_template,
julia_wrapper, 'println(jltex.formatter({code}))', julia_sub,
'ERROR:', 'WARNING:', ':{number}', True)
SubCodeEngine('julia', 'jl')
-CodeEngine('juliacon', 'julia', '.jl', '{julia} -e "using Weave; weave(\\"{File}.jl\\", \\"tex\\")"', '{body}\n',
+CodeEngine('juliacon', 'julia', '.jl', '{julia} --project=@. -e "using Weave; weave(\\"{File}.jl\\", \\"tex\\")"', '{body}\n',
'#+ term=true\n{code}\n', '', '',
'ERROR:', 'WARNING:', ':{number}', True, created='{File}.tex')
@@ -1537,7 +1537,7 @@ rust_sub = '''
CodeEngine('rust', 'rust', '.rs',
# The full script name has to be used in order to make Windows and Unix behave nicely
# together when naming executables. Despite appearances, using `.exe` works on Unix too.
- ['{rustc} --crate-type bin -o {File}.exe -L {workingdir} {file}.rs', '{File}.exe'],
+ ['{rustc} --crate-type bin -o "{File}.exe" -L "{workingdir}" {file}.rs', '"{File}.exe"'],
rust_template, rust_wrapper, '{{ let val = {{ {code} }}; println!("{{}}", rstex.formatter(val)); }}', rust_sub,
errors='error:', warnings='warning:', linenumbers='.rs:{number}',
created='{File}.exe')
diff --git a/Master/texmf-dist/source/latex/pythontex/pythontex.dtx b/Master/texmf-dist/source/latex/pythontex/pythontex.dtx
index f18d8d3fae0..38d44ffd9ed 100644
--- a/Master/texmf-dist/source/latex/pythontex/pythontex.dtx
+++ b/Master/texmf-dist/source/latex/pythontex/pythontex.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-% Copyright (C) 2012-2019 by Geoffrey M. Poore <gpoore@gmail.com>
+% Copyright (C) 2012-2021 by Geoffrey M. Poore <gpoore@gmail.com>
% ---------------------------------------------------------------------------
% 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 @@
%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
%<package>\ProvidesPackage{pythontex}
%<*package>
- [2019/09/22 v0.17 execute and typeset Python code and other languages]
+ [2021/06/06 v0.18 execute and typeset Python code and other languages]
%</package>
%
%<*driver>
@@ -168,6 +168,17 @@
%
%
%
+% \begin{changelog}{v0.18}{2021/06/06}
+% \begin{itemize}
+% \item \texttt{\string\inputpygments} now checks inputted files for modification, so that typeset code will correctly update when the source is changed (\#162).
+% \item Julia now uses project flag ``\texttt{-{}-project=@.}'' (\#157, \#158).
+% \item Fixed bug in processing Pygments options (\texttt{pygopt}) when a key is used without a value (\#181).
+% \item Some error handling for Windows was incompatible with other operating systems: replaced checks for \texttt{WindowsError} with checks for \texttt{OSError} (\#177).
+% \item Rust support is now compatible with document and working directory paths that contain spaces (\#167).
+% \end{itemize}
+% \end{changelog}
+%
+%
% \begin{changelog}{v0.17}{2019/09/22}
% \begin{itemize}
% \item Pygments syntax highlighting for the Python console (\texttt{pycon} lexer) now uses the \texttt{python3} option, and the default Python lexer is now \texttt{python3} (\#156).
@@ -891,7 +902,9 @@
%
% \DescribeMacro{\pys\oarg{session}\meta{opening~delim}\meta{code}\meta{closing~delim}}
%
-% This command performs variable and expression substitution, or string interpolation, on \meta{code}. Fields of the form |!{|\meta{expr}|}| in \meta{code} are replaced with the evaluated and printed output of \meta{expr}. The suffix |s| is an abbreviation of |sub|, for ``substitute.'' This command is useful for inserting Python-generated content in contexts where the normal |\py| and |\pyc| would not function or would be inconvenient due to the restrictions imposed by \LaTeX. Since Python processes \meta{code} and performs substitutions before the result is passed to \LaTeX, substitution fields may be anywhere.
+% This command performs variable and expression substitution, or string interpolation, on \meta{code}. Fields of the form |!{|\meta{expr}|}| in \meta{code} are replaced with the evaluated and printed output of \meta{expr}. Then the modified \meta{code} is inserted into the document and interpreted as \LaTeX. The suffix |s| is an abbreviation of |sub|, for ``substitute.''
+%
+% This command is useful for inserting Python-generated content in contexts where the normal |\py| and |\pyc| would not function or would be inconvenient due to the restrictions imposed by \LaTeX. Since Python processes \meta{code} and performs substitutions \emph{before} the result is passed to \LaTeX, substitution fields may be anywhere, including within parts of \meta{code} that will become \LaTeX\ comments.
%
% Literal exclamation points |!| in \meta{code} only need to be escaped when they immediately precede an opening curly brace |{|, or when they precede exclamation points that precede a brace. Escaping is performed by doubling. Thus, |!!{| would indicate a literal exclamation point followed by a literal curly brace (|!{|), not the beginning of a substitution field. And |!!!{| would indicate a literal exclamation point (|!!|) followed by a substitution field (|!{...}|). Because curly braces |{}| only have the meaning of field delimiters when immediately following a non-escaped exclamation point, curly braces never need to be escaped.
%
@@ -926,7 +939,7 @@
%
% \DescribeEnv{pysub~\oarg{session}\oarg{fancyvrb~settings}}
%
-% This environment performs variable and expression substitution, or string interpolation, on the enclosed code. Fields of the form |!{|\meta{expr}|}| in \meta{code} are replaced with the evaluated and printed output of \meta{expr}. See the description of the |\pys| command for details about substitution field syntax.
+% This environment performs variable and expression substitution, or string interpolation, on the enclosed code. Fields of the form |!{|\meta{expr}|}| in \meta{code} are replaced with the evaluated and printed output of \meta{expr}. See the description of the |\pys| command for details about substitution and the substitution field syntax.
%
%
%
@@ -1885,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.17}
+\newcommand{\pytx@packageversion}{0.18}
% \end{macrocode}
%
% \subsection{Required packages}
diff --git a/Master/texmf-dist/source/latex/pythontex/pythontex.ins b/Master/texmf-dist/source/latex/pythontex/pythontex.ins
index aab14011f7e..83dd081ef3a 100644
--- a/Master/texmf-dist/source/latex/pythontex/pythontex.ins
+++ b/Master/texmf-dist/source/latex/pythontex/pythontex.ins
@@ -25,7 +25,7 @@
This is a generated file.
-Copyright (C) 2012-2019 by Geoffrey M. Poore <gpoore@gmail.com>
+Copyright (C) 2012-2021 by Geoffrey M. Poore <gpoore@gmail.com>
--------------------------------------------------------------------------
This work may be distributed and/or modified under the
conditions of the LaTeX Project Public License, either version 1.3
diff --git a/Master/texmf-dist/tex/latex/pythontex/pythontex.sty b/Master/texmf-dist/tex/latex/pythontex/pythontex.sty
index afcad2243e1..5fa953f65d0 100644
--- a/Master/texmf-dist/tex/latex/pythontex/pythontex.sty
+++ b/Master/texmf-dist/tex/latex/pythontex/pythontex.sty
@@ -8,7 +8,7 @@
%%
%% This is a generated file.
%%
-%% Copyright (C) 2012-2019 by Geoffrey M. Poore <gpoore@gmail.com>
+%% Copyright (C) 2012-2021 by Geoffrey M. Poore <gpoore@gmail.com>
%% --------------------------------------------------------------------------
%% 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}
- [2019/09/22 v0.17 execute and typeset Python code and other languages]
+ [2021/06/06 v0.18 execute and typeset Python code and other languages]
\newcommand{\pytx@packagename}{PythonTeX}
-\newcommand{\pytx@packageversion}{0.17}
+\newcommand{\pytx@packageversion}{0.18}
\RequirePackage{fvextra}
\RequirePackage{etoolbox}
\RequirePackage{xstring}