Skip to content

Commit 83a8d53

Browse files
committed
virtual environment and pycharm and requirements.txt
1 parent 8f7b6f3 commit 83a8d53

15 files changed

+253
-13
lines changed

draft.sh

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/bin/bash
2+
3+
# Make a draft of the book.
4+
5+
# strict error handling
6+
set -o pipefail # trace ERR through pipes
7+
set -o errtrace # trace ERR through 'time command' and other functions
8+
set -o nounset # set -u : exit the script if you try to use an uninitialized variable
9+
set -o errexit # set -e : exit the script if any statement returns a non-true return value
10+
11+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Welcome to the draft building script."
12+
13+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): First deleting the git cache."
14+
rm -rf __git__ || true
15+
16+
currentDir="$(pwd)"
17+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): We are working in directory: '$currentDir'."
18+
scriptDir="$currentDir/scripts"
19+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): The script directory is '$scriptDir'."
20+
21+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): We delete all left over data."
22+
rm "book.pdf" || true
23+
rm -rf "$currentDir/website" || true
24+
25+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): We setup a virtual environment in a temp directory."
26+
venvDir="$(mktemp -d)"
27+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Got temp dir '$venvDir', now creating environment in it."
28+
python3 -m venv --upgrade-deps --copies "$venvDir"
29+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Activating virtual environment in '$venvDir'."
30+
source "$venvDir/bin/activate"
31+
export PYTHON_INTERPRETER="$venvDir/bin/python3"
32+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Setting python interpreter to '$PYTHON_INTERPRETER'."
33+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): We install all required Python packages from requirements.txt to virtual environment in '$venvDir'."
34+
"$PYTHON_INTERPRETER" -m pip install --no-input --timeout 360 --retries 100 -r requirements.txt
35+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Finished installing the requirements, now printing all installed packages."
36+
pip freeze
37+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Finished printing all installed packages."
38+
39+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): We now execute the pdflatex compiler script."
40+
"$scriptDir/pdflatex.sh" "book.tex" quick
41+
42+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Deactivating virtual environment."
43+
deactivate
44+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Deleting virtual environment."
45+
rm -rf "$venvDir"
46+
47+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): We have finished the book building process."
48+
evince book.pdf

scripts/pdflatex.sh

+11-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## pdflatex Compiler Script
44
## $1 the document to compile
5+
## $2 == "quick" for incomplete compile
56

67
# strict error handling
78
set -o pipefail # trace ERR through pipes
@@ -120,6 +121,7 @@ echo "$(date +'%0Y-%0m-%0d %0R:%0S'): We will now perform runs of the tool chain
120121

121122
watchFileContents=""
122123
oldWatchFileContents="old"
124+
quickArg="${2:-}"
123125
cycle=0
124126
additional=1
125127

@@ -221,7 +223,7 @@ while (("$additional" >= 0)) ; do
221223
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): '$auxFile' does not exist, so we do not need to apply makeglossaries."
222224
fi
223225

224-
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Now loading the contents should no longer change when the built is complete."
226+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Now loading the contents that should no longer change when the built is complete."
225227
for suffix in "acn" "acr" "alg" "bbl" "bcf" "glg" "glo" "gls" "idx" "ind" "ist""slg" "slo" "sls" "toc"; do
226228
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Now looking for '$suffix' files."
227229
for theFile in *.$suffix; do
@@ -235,6 +237,13 @@ while (("$additional" >= 0)) ; do
235237

236238
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Finished build cycle $cycle."
237239

240+
if [ "$quickArg" == "quick" ] ; then
241+
if (("$cycle" > 1)) ; then
242+
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Quick and incomplete compilation was selected, so we stop after now (cycle $cycle)."
243+
break
244+
fi
245+
fi
246+
238247
if (("$cycle" > 640)) ; then
239248
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): Something odd is happening: We have performed $cycle cycles. That's too many. Let's quit."
240249
break
@@ -254,7 +263,7 @@ echo "$(date +'%0Y-%0m-%0d %0R:%0S'): The tool chain has been applied until noth
254263
latexWarningsCount=0
255264
latexWarningString=""
256265
logFile="$documentName.log"
257-
if [ -f "$logFile" ]; then
266+
if [ -f "$logFile" ] && [ "$quickArg" != "quick" ]; then
258267
echo "$(date +'%0Y-%0m-%0d %0R:%0S'): We found the log file '$logFile' and check its contents."
259268
fileContents="$(<$logFile)"
260269

styles/listing.sty

+10
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,16 @@ breaklines=true%
247247
\gitCode{#1}{#2}{}{#3}{#4}{,style=bat_style}%
248248
}%
249249
%
250+
%%
251+
%% Use latexgit to place a plain text listing.
252+
%% #1 the git repository
253+
%% #2 the local path
254+
%% #3 the label (lst: will be pre-pended)
255+
%% #4 the caption
256+
\protected\gdef\gitText#1#2#3#4{%
257+
\gitCode{#1}{#2}{}{#3}{#4}{,style=text_style}%
258+
}%
259+
%
250260
%% Use latexgit to place a listing with program output.
251261
%% #1 the git repository
252262
%% #2 the local path

text/main/packages/packages.tex

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
%
2-
\hsection{Packages}%
2+
\hsection{Using Packages}%
33
%
44
\begin{figure}%
55
\centering%
@@ -15,5 +15,7 @@
1515
In this section of the book, we will focus on how we can obtain and use packages.%
1616
%
1717
\hinput{pipAndVenv}{pipAndVenv.tex}%
18+
\hinput{requirementsFiles}{requirementsFiles.tex}%
19+
\hinput{venvAndPycharm}{venvAndPycharm.tex}%
1820
\endhsection%
1921
%

text/main/packages/pipAndVenv/pipAndVenv.tex

+5-10
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,22 @@
3636
%
3737
\usefulTool{venv}{The module \venv\ is used for creating and managing \pglspl{virtualEnvironment} under \python.}%
3838
%
39-
%
4039
\gitPython{\programmingWithPythonCodeRepo}{packages/numpy_user.py}{--args format}{packages:numpy_user}{%
4140
A small \python\ script using the \numpy\ library.}%
4241
%
4342
For demonstration purposes, let us assume that we have written a program using the \pgls{package} \numpy~\cite{HMvdWGVCWTBSKPHvKBHFdRWPGMSRWAGO2020APWN,DBvR2024ITN,J2018NPSCADSAWNSAM}.
4443
The small program in \cref{lst:packages:numpy_user} only creates and prints a \numpy\ array, but for this, obviously, \numpy\ is needed.
4544
\numpy\ is not available in fresh \python\ installations and needs to be installed so that we can run our program.
46-
This will be the example that we will use to demonstrate the use of \pglspl{virtualEnvironment} in the following sections.%
47-
%
48-
%
49-
\hsection{pip and Virtual Environments in the Command Line}%
50-
%
45+
This will be the example that we will use to demonstrate the use of \pglspl{virtualEnvironment} in the following sections.
46+
5147
As prerequisites to install \pglspl{package} in \pglspl{virtualEnvironment}, we need to make sure that both \pip\ and \venv\ are installed on our system.
5248
The procedures for both differ under \linux\ and \windows.
5349
Using \pip\ and \venv\ is often done in the \pgls{terminal}, i.e., by typing commands or executing shell scripts.
5450
This, naturally, too works differently under \linux\ and \windows.
5551
We therefore will briefly explore how to achieve these things under both operating systems.%
5652
%
5753
\FloatBarrier%
58-
\hsection{pip and Virtual Environments in \ubuntu\ \linux}%
54+
\hsection{pip and Virtual Environments in Ubuntu Linux}%
5955
%
6056
\begin{figure}%
6157
\centering%
@@ -206,7 +202,7 @@
206202
\FloatBarrier%
207203
\endhsection%
208204
%
209-
\hsection{pip and Virtual Environments under \windows}%
205+
\hsection{pip and Virtual Environments under Windows}%
210206
%
211207
\begin{figure}%
212208
\centering%
@@ -351,8 +347,7 @@
351347
%
352348
\endhsection%
353349
%
354-
\FloatBarrier%
355-
\endhsection%
350+
\FloatBarrier
356351
%
357352
\endhsection%
358353
%
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
%
2+
\hsection{Requirements Files}
3+
%
4+
\gitPython{\programmingWithPythonCodeRepo}{packages/requirements.txt}{--args format}{packages:requirementstxt}{%
5+
A requirements file demanding that version~\textil{1.26.4} of \numpy\ be installed.}%
6+
%
7+
\gitBashAndOutput{\programmingWithPythonCodeRepo}{packages}{numpy_user_venv_req.sh}{packages:numpy_user_venv_req_sh}{%
8+
A script that runs our example program using a \pgls{virtualEnvironment} created by using the \textil{requirements.txt} file given in \cref{lst:packages:requirementstxt}.}%
9+
%
10+
It is very normal that our projects require multiple different \pglspl{package}.
11+
Sometimes, they require specific versions of specific \pglspl{package}.
12+
Instead of manually installing these dependencies with \pip\ every time we want to use our program, it makes sense to \emph{write them down}.
13+
Indeed, the dependencies of an application are a very important part of the documentation.%
14+
%
15+
\begin{sloppypar}%
16+
Requirements files offer a very simple format for this purpose.
17+
They are usually called \textil{requirements.txt} and reside in the root folder of a project.
18+
As their name implies, they are simple text files.
19+
Each of their lines lists one \pgls{package} that is required, optionally with version constraints.%
20+
\end{sloppypar}%
21+
%
22+
\Cref{lst:packages:requirementstxt} gives a trivial example of such a file.
23+
It contains the line \textil{numpy==1.26.4}.
24+
This means that \numpy\ of exactly the version~1.26.4 is required for our application.
25+
Had we written \textil{numpy>=1.26.4}, then a larger version of \numpy\ would also have been OK.
26+
The other operators, \textil{>}, \textil{<}, and~\textil{<=} can be used as well and have their natural corresponding meaning.
27+
If we had wanted, we could have written \textil{matplotlib} in the second line of our \textil{requirements.txt} file, which would then have meant that, besides \numpy\ of version~\textil{1.26.4}, the package \matplotlib\ is needed as well.
28+
Writing only \textil{matplotlib} would be interpreted as \inQuotes{find the highest version of \matplotlib\ that is compatible with \numpy\ version~1.26.4.}
29+
But we only need one package, \numpy, so our file just has a single line.
30+
31+
In \cref{lst:packages:numpy_user_venv_req_sh}, we present a version of the script that we used to set up a virtual environment and run our two-line \numpy\ program under \ubuntu\ \linux~(see \cref{lst:packages:numpy_user_venv_req_sh}.)
32+
The only difference is that we now do not write \bashil{pip install numpy} but instead write \bashil{pip install -r requirements.txt}.
33+
This tells \pip\ to install \emph{all} the requirements from the requirements file \textil{requirements.txt}.
34+
Under \windows, it works exactly the same.
35+
36+
Having a \textil{requirements.txt} file in the root directory of your project is very useful.
37+
It automatically informs anybody who works with your code or who uses your program which versions of which \pglspl{package} they need.
38+
Therefore, it makes sense to specify \pgls{package} versions as precisely as possible in \textil{requirements.txt}.%
39+
%
40+
\bestPractice{requirementsTxt}{%
41+
The \pglspl{package} that a \python\ project requires or depends on should be listed in a file called \textil{requirements.txt} in the root folder of the project.}%
42+
%
43+
\bestPractice{requirementsTxtExact}{%
44+
All required \pglspl{package} in a \textil{requirements.txt} file should be specified with the exact version, i.e., in the form of~\textil{package==version}. %
45+
This ensures that the behavior of the project can be exactly replicated on other machines. %
46+
It rules out that errors can be caused due to incompatible versions of dependencies, because it allows the users to exactly replicate the set up of the machine on which the project was developed.%
47+
}%
48+
%
49+
\FloatBarrier%
50+
\endhsection%
51+
%
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
%
2+
\hsection{Virtual Environments in PyCharm}%
3+
%
4+
\begin{figure}%
5+
\centering%
6+
%
7+
\subfloat[][%
8+
We create a new project in \pycharm\ and select a \pgls{virtualEnvironment} as \menu{Custom Environment}. %
9+
We click~\menu{Create}.%
10+
\label{fig:venvPycharm1}%
11+
]{\tightbox{\includegraphics[width=0.48\linewidth]{\currentDir/venvPycharm1}}}%
12+
%
13+
\strut\hfill\strut%
14+
%
15+
\subfloat[][%
16+
Since I selected the folder where the other files (\textil{requirements.txt}, \textil{numpy_user.py}, \dots) are already located, \pycharm\ asks whether this is OK. %
17+
We select \menu{Create from Existing Sources} if asked.%
18+
\label{fig:venvPycharm2}%
19+
]{\tightbox{\includegraphics[width=0.48\linewidth]{\currentDir/venvPycharm2}}}%
20+
%
21+
\\[10pt]%
22+
%
23+
\subfloat[][%
24+
Let's take a look at \textil{requirements.txt}. %
25+
We double-click on this file.%
26+
\label{fig:venvPycharm3}%
27+
]{\tightbox{\includegraphics[width=0.48\linewidth]{\currentDir/venvPycharm3}}}%
28+
%
29+
\strut\hfill\strut%
30+
%
31+
\subfloat[][%
32+
It contains the one line \textil{numpy==1.26.4}, which means that our project requires \numpy\ in version~1.26.4.%
33+
\label{fig:venvPycharm4}%
34+
]{\tightbox{\includegraphics[width=0.48\linewidth]{\currentDir/venvPycharm4}}}%
35+
%
36+
%
37+
\caption{Using \textil{requirements.txt} and \pglspl{virtualEnvironment} in \pycharm~(part~1).}%
38+
\label{fig:venvPycharmA}%
39+
\end{figure}%
40+
%
41+
\begin{figure}%
42+
\ContinuedFloat%
43+
\centering%
44+
%
45+
\subfloat[][%
46+
We now click on \textil{numpy_user.py} and get informed that required \pglspl{package} are missing. %
47+
We can install them into our project's \pgls{virtualEnvironment} by clicking \menu{Install requirement}. %
48+
Notice:~This question could also have popped up when we opened \textil{requirements.txt}, in which case we would have installed the requirements then.%
49+
\label{fig:venvPycharm5}%
50+
]{\tightbox{\includegraphics[width=0.48\linewidth]{\currentDir/venvPycharm5}}}%
51+
%
52+
\strut\hfill\strut%
53+
%
54+
\subfloat[][%
55+
We get informed that the required packages were successfully installed.%
56+
\label{fig:venvPycharm6}%
57+
]{\tightbox{\includegraphics[width=0.48\linewidth]{\currentDir/venvPycharm6}}}%
58+
%
59+
\\[10pt]%
60+
%
61+
\subfloat[][%
62+
We right-click on \textil{numpy_user.py} and click on~\menu{Run \inSQuotes{numpy\_user.py}}.%
63+
\label{fig:venvPycharm7}%
64+
]{\tightbox{\includegraphics[width=0.48\linewidth]{\currentDir/venvPycharm7}}}%
65+
%
66+
\strut\hfill\strut%
67+
%
68+
\subfloat[][%
69+
Our program is executed without error and produces the expected output.%
70+
\label{fig:venvPycharm8}%
71+
]{\tightbox{\includegraphics[width=0.48\linewidth]{\currentDir/venvPycharm8}}}%
72+
%
73+
%
74+
\caption{Using \textil{requirements.txt} and \pglspl{virtualEnvironment} in \pycharm~(part~2).}%
75+
\label{fig:venvPycharmB}%
76+
\end{figure}%
77+
%
78+
The \pgls{IDE} \pycharm\ also supports using \pglspl{virtualEnvironment} and \textil{requirements.txt} files.
79+
Let us here demonstrate this on the example program that requires \numpy\ which was given as \cref{lst:packages:numpy_user} and \textil{requirements.txt} file given in \cref{lst:packages:requirementstxt}.
80+
In \cref{fig:venvPycharmA}, we work through the steps to create and manage a project with a \pgls{virtualEnvironment} in \pycharm\ on their basis.
81+
82+
First, we need to create a new project~(\cref{fig:venvPycharm1}).
83+
For this purpose, we already copied the files \pglspl{virtualEnvironment} and \textil{requirements.txt} into a folder~(here:~\textil{/tmp/packages}).
84+
In the \menu{New Project} dialog of \pycharm, we select this folder as \menu{Location:}.
85+
As \menu{Interpreter type:}, we choose \menu{Custom Environment} and as \menu{Environment:}, we pick \menu{Generate new}.
86+
As \menu{Type:}, we choose \menu{Virtualenv}.
87+
The default \menu{Location} is \textil{.venv} inside our project directory and we keep this setting.
88+
After clicking \menu{Create}, a new project is created.
89+
90+
Well, almost:
91+
\Cref{fig:venvPycharm2} reminds me that I copied some files into the project folder before creating the project.
92+
\pycharm\ wants to make sure that this is right and asks me so.
93+
As answer, I click~\menu{Create from Existing Sources}.
94+
95+
We now are in the normal \pycharm\ project view in~\cref{fig:venvPycharm3}.
96+
All the files that I placed into the folder are there and also a \textil{.venv} directory has been created.
97+
Notice that you could as well create an empty project and copy the files there.
98+
99+
We click on \textil{requirements.txt} and it opens in~\cref{fig:venvPycharm4}.
100+
Indeed, the file prescribes a single requirement, \numpy\ in version~1.26.4.
101+
102+
When we click on the file \textil{numpy_user.py} to open it in~\cref{fig:venvPycharm5}, we notice a yellow bar at the top of the file's contents.
103+
This bar tells us that the required package \numpy\ is missing.
104+
It offers us the two choices to either \menu{Install requirement} or to \menu{Ignore requirement}.
105+
We select the first option and click it.
106+
Notice that this same yellow bar could also have appeared when we opened \textil{requirements.txt}.
107+
I am not sure why it appears only now.
108+
Either way, we accept the choice to install the requirement.
109+
110+
In \cref{fig:venvPycharm6}, we are informed that the installation was successful.
111+
The small overlay also tells us that \numpy\ was installed in version~1.26.4, as prescribed by the \textil{requirements.txt} file.
112+
At the time of this writing, \numpy\ is already out at version~2.2.1, which would have been used if we had just installed it without version specification.
113+
So this confirms that, indeed, our \textil{requirements.txt} is used.
114+
We also can see that the red underline under \pythonilIdx{numpy} that was present in \cref{fig:venvPycharm5} is now gone in \cref{fig:venvPycharm6}, because now the package and corresponding modules can be loaded without error.
115+
116+
As final check that everything went well we run our program \textil{numpy_user.py} in \cref{fig:venvPycharm7}.
117+
We right-click the file in three view on the left-hand side of the window.
118+
A popup menu appears, in which we click on \menu{Run \inSQuotes{numpy\_user.py}}.
119+
We could just as well have pressed \keys{\ctrl+\shift+F10}.
120+
Our program is executed and the expected output appears (\cref{fig:venvPycharm8}).
121+
All is well.%
122+
%
123+
\FloatBarrier%
124+
\endhsection%
125+
%
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading

0 commit comments

Comments
 (0)