Exsheets and pythontex compatibility
The question
and solution
environments use internally the __exsheets_questions_internal:
and __exsheets_solution_internal:
environments that are defined with \NewEnviron
from the environ
package.
The contents of an environment defined with \NewEnviron
is absorbed as a macro argument, which makes any verbatim-like command or environment illegal inside it.
You'd get the same problem with \verb
or verbatim
in a question
or solution
environment.
The package documentation discusses the problem in Part III, where the exsheets-listing
subpackage is described. Maybe something like that can be done also for allowing pycode
environments, but the syntax of lstquestion
and lstsolution
doesn't seem like the better for complex usage.
egreg's answer covers most of the details. Here is a little additional information.
The lstquestion
and lstsolution
environments allow listings, by writing environment contents to an auxiliary file and then reading back the auxiliary file at the appropriate point. Since the environment is saved as a file rather than captured as a macro argument, verbatim material works fine. The same approach could be applied to allow pycode
and similar environments to function. You would need versions of question
and solution
that write their contents to an auxiliary file rather than using \NewEnviron
. This is essentially the same approach that beamer
takes with its fragile
option.
As egreg has noted, \verb
wouldn't work within a question
or solution
environment. This might raise the question of why \pyc
and similar pythontex commands do work, since in general they need verbatim arguments. The answer is that \pyc
works very differently from \verb
. \pyc
and similar commands use \scantokens
to retokenize their arguments, which essentially restores the arguments to verbatim status. However, since the arguments are initially tokenized when the contents of the environment is read as a macro argument, this approach fails if the argument to \pyc
contains a #
or %
character, or an unmatched brace. (I have some ideas about working around this in a future version of pythontex with a properly defined \#
, \%
, \{
, and \}
.)
That explains how something like \pyc{...}
works, where the argument is delimited by curly braces. The case where another character is used (for example, \pyc/.../
) is a little trickier. \pyc
takes the first delimiting character and, on the fly, creates a macro that will capture everything until the character appears again. Then it invokes this new macro to actually capture the argument. This makes the argument-capturing mechanism essentially catcode-independent (again, with the exception of #
, %
, and unmatched braces).