[Tex/LaTex] pyLaTeX – Create custom command

pythonpythontex

I'm trying to make the LaTeX command below utilizing the pyLaTeX library in a hopes to call this function later in the document.

\newcommand*\Entry[2]{%
  \sffamily#1 & #2}

I'm attempting to follow along with the "Own Commands Example" from the official pyLaTeX docs but have some questions. The relevant parts of the doc follow below:

class ExampleCommand(CommandBase):
    """
    A class representing a custom LaTeX command.

    This class represents a custom LaTeX command named
    ``exampleCommand``.
    """

    _latex_name = 'exampleCommand'
    packages = [Package('color')]

doc = Document()
with doc.create(Section('Custom commands')):
    # Define the new command
    new_comm = UnsafeCommand('newcommand', '\exampleCommand', options=3,
                             extra_arguments=r'\color{#1} #2 #3 \color{black}')
    doc.append(new_comm)

    # Use our newly created command with different arguments
    doc.append(ExampleCommand(arguments=Arguments('blue', 'Hello', 'World!')))
    doc.append(ExampleCommand(arguments=Arguments('green', 'Hello', 'World!')))
    doc.append(ExampleCommand(arguments=Arguments('red', 'Hello', 'World!')))

Which yeilds the LaTeX:

\newcommand{\exampleCommand}[3]{\color{#1} #2 #3 \color{black}}%
\exampleCommand{blue}{Hello}{World!}%
\exampleCommand{green}{Hello}{World!}%
\exampleCommand{red}{Hello}{World!}

My question is what is the purpose of the Class in this example? Is it only required because we are importing a LaTeX package? Would such a class be required for the command I am trying to create?

Furthermore, if the class is establishing the command than what is the purpose of the new_comm function? It isn't called at any other time in the code example so I am unsure of its purpose.

Thanks

Best Answer

You don't necessarily need to use the functions and classes that PyLaTeX provides. You can add any arbitrary text or LaTeX code to your document as strings using the NoEscape wrapper. To add a package there is doc.packages.append, for other preamble code such as command definitions (which are generally also in the preamble) there is doc.preamble.append, for the document itself doc.append can be used.

MWE for both the manual example and your own command:

from pylatex import Document, Package, NoEscape

doc = Document()
doc.packages.append(Package('color'))
doc.preamble.append(NoEscape(r'\newcommand{\exampleCommand}[3]{\color{#1} #2 #3 \color{black}}'))
doc.append(NoEscape(r'\exampleCommand{blue}{Hello}{World!}'))

doc.preamble.append(NoEscape(r'\newcommand*\Entry[2]{\sffamily#1 & #2}'))
doc.append(NoEscape(r'\begin{tabular}{ll}'))
doc.append(NoEscape(r'\Entry{abc}{123}\\'))
doc.append(NoEscape(r'\end{tabular}'))

doc.generate_tex('pycommands')

Generated pycommands.tex:

\documentclass{article}%
\usepackage[T1]{fontenc}%
\usepackage[utf8]{inputenc}%
\usepackage{lmodern}%
\usepackage{textcomp}%
\usepackage{lastpage}%
\usepackage{color}%
%
\newcommand{\exampleCommand}[3]{\color{#1} #2 #3 \color{black}}%
\newcommand*\Entry[2]{\sffamily#1 & #2}%
%
\begin{document}%
\normalsize%
\exampleCommand{blue}{Hello}{World!}%
\begin{tabular}{ll}%
\Entry{abc}{123}\\%
\end{tabular}%
\end{document}

Result:

enter image description here

However, PyLaTeX is not intended to be just a wrapper around regular LaTeX code. The idea is that many relevant parts of LaTeX syntax are formalized, so LaTeX commands can be easily called with arguments stored in Python data structures, and that the document itself can be generated in a flexible way from Python code.

For this intended use you do need the classes and commands. The CommandBase class from the manual provides not only a way to indicate that this command needs the color package, but it also generates the interface for the command that allows to provide the arguments as a list of Python strings or variables, i.e., the ExampleCommand(arguments=Arguments('blue', 'Hello', 'World!')) syntax.

The new_comm part results in adding the \newcommand code to the document, this is a separate part of the code because it is only needed for custom commands. The class definition however is needed for all commands if you want to use the syntax in the manual (except for commands implemented by PyLaTeX itself, such as HugeText or TextColor).

Alternatively, you can use the generic Command class and provide the LaTeX name as first argument. In that case you don't need a separate class definition. Example:

doc.append(Command('exampleCommand',arguments=Arguments('blue','Hello','World')))