How to keep indentations in Python code copied from LaTeX PDF?

The pdfTeX has command \pdffakespace to insert a space into the document. This space is invisible, but it is taken into account during text copying.

So, my first idea was to insert \pdffakespace after each space at the beginning of lines, but unfortunately, it results in spaces doubling in the copied text (one space comes from \pdffakespace and another is generated by Acrobat Reader automatically from TeX's \hskip).

Next idea was to count the number of leading spaces in the line and insert the necessary number of \pdffakespace after those spaces. Unfortunately, Acrobat Reader trims that spaces to a single one (in spite of the fact that the sequence of space commands [( )]TJ is actually presented in the generated PDF file).

But finally, I've found a tricky solution: group spaces into pairs and replace them with a sequence of \pdffakespace and \hskip of double space width. Starting with a standard preamble to make @ a letter

\makeatletter

we redefine the \@verbatim command by adding \hook@par at the end of \par command definition (to process text after line break):

\def\@verbatim{\trivlist \item\relax
  \if@minipage\else\vskip\parskip\fi
  \leftskip\@totalleftmargin\rightskip\z@skip
  \parindent\z@\parfillskip\@flushglue\parskip\z@skip
  \@@par
  \language\l@nohyphenation
  \@tempswafalse
  \def\par{%
    \if@tempswa
      \leavevmode \null \@@par\penalty\interlinepenalty
    \else
      \@tempswatrue
      \ifhmode\@@par\penalty\interlinepenalty\fi
    \fi\hook@par}% <=== HERE
  \let\do\@makeother \dospecials
  \obeylines \verbatim@font \@noligs
  \everypar \expandafter{\the\everypar \unpenalty}%
}

Then we create a counter to count spaces at the beginning of lines

\newcount\nspaces

reset this counter at the beginning of lines, and count the sequence of spaces

\def\hook@par{\nspaces=0\relax\check@space}
\def\check@space{\futurelet\@let@token\do@check@space}
\def\do@check@space{%
  \ifx\@let@token\@xobeysp%
    \advance\nspaces 1%
    \expandafter\skip@space%
  \else%
    \ifnum\nspaces>0%
      \print@spaces%
    \fi%
  \fi}
\def\skip@space#1{\check@space}

And finally, we print paired spaces (with a special treat for the odd number of spaces, in this case, we finally out \pdffakespace following a single-space \hskip that will be merged with the previous \hskip and results in a single space during text copying)

\def\print@spaces{%
  \leavevmode\nobreak
  \loop%
    \pdffakespace%
    \nobreak\hskip\dimexpr 2\fontdimen2\font\relax%
    \advance\nspaces by -2\relax%
  \unless\ifnum\nspaces<2\repeat%
  \ifnum\nspaces>0%
    \nobreak\hskip\fontdimen2\font\relax%
    \pdffakespace%
  \fi}

In the end, don't forget to restore @ back:

\makeatother

That's all. Voilà.