4

I am writing a package that optionally uses the pythontex package. The pythontex package defines an environment pycode which allows you to execute Python code before \begin{document}. As far as I can see, putting the pycode environment within a macro is impossible, so I have to put it in regardless of whether the user wants to use Pythontex or not, and define or redefine it in case the user doesn't want to use it. In that case, I would have to define it in a way that ignores all the code written within the environment and that can be put into the preamble (or rather, can be executed at the loading of my package.)

MWE:

\RequirePackage{etoolbox}
\RequirePackage{xstring}
\RequirePackage{letltxmacro}

\newcommand{\@pythonbool}{false} %This tells us whether the python option is enabled or not.
\newcommand{\@pycodedefined}{false} %This tells us whether the environment pycode is defined at the loading of this style file or not.

\DeclareOption{python}{
\renewcommand{\@pythonbool}{true}
}

\ProcessOptions\relax

\expandafter\ifstrequal\expandafter{\@pythonbool}{false}{
\ifcsmacro{pycode}{
    \renewcommand{\@pycodedefined}{true}
    \LetLtxMacro{\@oldpy}{\pycode}
    \LetLtxMacro{\@oldendpy}{\endpycode}
    \renewenvironment{pycode}{}{} % If pycode is defined (because Pythontex is used), but the package should not use python, this will completely disregard anything in a pycode environment. We will correctly redefine pycode after the code to be disregarded. This is neccessary because we can't put the pycode environment inside a conditional. Arguably, we could also let the code execute, since it doesn't print anything, and so will not change the output, but this is cleaner since we avoid possible naming conflicts. I don't know if it also makes python run less often, which would be a plus too.
}{
    \newenvironment{pycode}{}{} % If pycode is undefined (because Pythontex isn't used), this prevents errors upon Latex encountering the pycode environment, which we otherwise can't, since we can't simply put the pycode environment  into a conditional.
}
}{ \RequirePackage{pythontex}
}

\begin{pycode}
some code
\end{pycode}

\expandafter\ifstrequal\expandafter{\@pycodedefined}{true}{
    \LetLtxMacro{\pycode}{\@oldpy}
    \LetLtxMacro{\endpycode}{\@oldendpy}}{}

The specific point I'm interested in is how I can stop my new definition of the environment from trying to print the code part at all.

Edit: The best way to do this seems to be a command that tells latex to ignore everything between it and its counterpart, but I wouldn't know how to define one.

cgnieder
  • 66,645
sgf
  • 561

1 Answers1

3

You could define a package option called nopython and provide the following code in the preamble.

\usepackage{comment}
\DeclareOption{nopython}{\excludecomment{pycode}}

Do note the syntactic requirement, stated in the package's user guide, that

The opening and closing commands [of the environment] should appear on a line of their own. No starting spaces, nothing after it.

Applying this syntactic requirement to your document, this means that all \begin{pycode} and \end{pycode} directives must occur on lines of their own, without any starting spaces.


A full MWE, which takes into account new information that the OP uses the scrartcl document class:

\documentclass{scrartcl} 
\usepackage{pythontex} % comment this line out if **not** using PythonTeX
\makeatletter
\AtBeginDocument{\@ifpackageloaded{pythontex}{}{%
  \usepackage{comment} 
  \excludecomment{pycode}}}
\makeatother

\begin{document} 
\begin{pycode} 
Some code. 
\end{pycode} 
Some text. 
\end{document}
Mico
  • 506,678
  • That seems like a very simple way of achieving it. Your code won't work however, since you can't use packages within DeclareOption, or so I have been told. – sgf Mar 30 '17 at 12:28
  • Also, can I later do \includecomment{pycode} so pycode works again as before? – sgf Mar 30 '17 at 12:31
  • 1
    Sweet! I know how to change your code to work, I just thought someone might try it as-is, so I thought it might be a good idea to point it out. – sgf Mar 30 '17 at 13:51
  • Actually, excludecomment doesn't seem to do the trick, it gives me "\begin{document} was ended by \end{VerbatimOut}" – sgf Mar 30 '17 at 14:25
  • Changed it to comply, but it still gives me the same error (and it works with other environments, I checked.) – sgf Mar 30 '17 at 14:46
  • Your code doesn't load pythontex in the first place, so I suspect it is due to that. – sgf Mar 30 '17 at 16:00
  • There is always the chance that someone is using PythonTeX but doesn't want my package to use it, in which case PythonTex might be loaded by the actual tex file but not by my package. As to posting example code: I already have a satisfactory solution, clemens's suggestion in his comment, and I don't think the question is the place to show why one answer won't work if a correct one has already be given, so I'll try to trim the code to a minimum so it fits inside a comment. – sgf Mar 30 '17 at 16:29
  • \documentclass{scrartcl} \usepackage{pythontex} \usepackage{comment}

    \excludecomment{pycode}

    \begin{document} \begin{pycode} Some code. \end{pycode}

    Some text.

    \end{document}

    – sgf Mar 30 '17 at 16:29
  • This won't work, even if \begin{pycode} and \end{pycode} are the only things in their respective lines. – sgf Mar 30 '17 at 16:30
  • Thanks for providing the piece of information that you use the scrartcl document class. I've posted a new MWE. – Mico Mar 30 '17 at 17:31
  • This still runs the code within the pycode environment through python, for whatever reason, so it still doesn't work. – sgf Mar 30 '17 at 23:52
  • @sgf - The pycode environment is not processed if the pythontex package isn't loaded. Isn't that what you wanted? – Mico Mar 31 '17 at 03:51
  • No, what I wanted was to be able to have the pycode environment completely disregard its content both with pythontex loaded and with pythontex not loaded, since I can't (or don't want to) control whether the user of my package loads it, even if my package doesn't - a user might want to use pythontex for other stuff, but not want my package to run it. – sgf Mar 31 '17 at 09:33
  • @sgf - I give up. It appears I'm doing nothing but waste your time -- and my own. I think you should edit your posting thoroughly and explain concisely what you want to achieve. Maybe somebody else will finally understand what you're trying to do. It's not going to be me, for sure. – Mico Mar 31 '17 at 09:45