about summary refs log tree commit diff
path: root/doc
diff options
context:
space:
mode:
authorBenjamin Hipple <bhipple@protonmail.com>2020-05-09 19:11:09 -0400
committerFrederik Rietdijk <freddyrietdijk@fridh.nl>2020-05-15 22:43:16 +0200
commitc88290789c06e19453375ad85f3cd1d417b07ae9 (patch)
tree12ce30da42dc3cd0e189893f6a2f2e55c6ec2b59 /doc
parent84765451c2f6b1205694ab4f0fecbd04e69a8340 (diff)
downloadnixlib-c88290789c06e19453375ad85f3cd1d417b07ae9.tar
nixlib-c88290789c06e19453375ad85f3cd1d417b07ae9.tar.gz
nixlib-c88290789c06e19453375ad85f3cd1d417b07ae9.tar.bz2
nixlib-c88290789c06e19453375ad85f3cd1d417b07ae9.tar.lz
nixlib-c88290789c06e19453375ad85f3cd1d417b07ae9.tar.xz
nixlib-c88290789c06e19453375ad85f3cd1d417b07ae9.tar.zst
nixlib-c88290789c06e19453375ad85f3cd1d417b07ae9.zip
doc: Rewrite python onboarding tutorials in manual
Based on some feedback in #87094 and discussion with @fridh, this re-organizes
the onboarding tutorial in the Nixpkgs manual's python section, so that we start
with the simplest, most ad-hoc examples and work our way up. This progresses
from:

1. How to create an temporary python env at the cmdline, then
2. How to create a specific python env for a single script, then
3. How to create a specific python env for a project in a shell.nix, then
4. How to install a specific python env globally on the system or in a user profile.

Additionally, I've tried to standardize on some of the "best practice" ways of
doing things:

1. Instead of saying that this command style is "supported but strongly not
   discouraged", I've just deleted it to avoid confusion.

   Bad:  nix-shell -p python38Packages.numpy python38Packages.toolz
   Good: nix-shell -p 'python38.withPackages(ps: with ps; [ numpy toolz ])'

2. In the portion where we show how to add stuff to the user's
   `XDG_CONFIG_HOME`, use overlays instead of `config.nix`. The former can do
   everything the latter can do, but is also much more generic and powerful,
   because it can compose with other files, compose with other envs, compose
   with overlays that do things like swap whether tensorflow and pytorch are
   built openblas/mkl/cuda stacks, and so on. The user is eventually going to
   see the overlay, so to avoid confusion let's standardize on it.
Diffstat (limited to 'doc')
-rw-r--r--doc/languages-frameworks/python.section.md392
1 files changed, 254 insertions, 138 deletions
diff --git a/doc/languages-frameworks/python.section.md b/doc/languages-frameworks/python.section.md
index 00d5d0ff04cf..35ea480e6b94 100644
--- a/doc/languages-frameworks/python.section.md
+++ b/doc/languages-frameworks/python.section.md
@@ -36,121 +36,191 @@ The Nix and NixOS manuals explain how packages are generally installed. In the
 case of Python and Nix, it is important to make a distinction between whether the
 package is considered an application or a library.
 
-Applications on Nix are typically installed into your user
-profile imperatively using `nix-env -i`, and on NixOS declaratively by adding the
-package name to `environment.systemPackages` in `/etc/nixos/configuration.nix`.
-Dependencies such as libraries are automatically installed and should not be
-installed explicitly.
-
-The same goes for Python applications and libraries. Python applications can be
-installed in your profile. But Python libraries you would like to use for
-development cannot be installed, at least not individually, because they won't
-be able to find each other resulting in import errors. Instead, it is possible
-to create an environment with `python.buildEnv` or `python.withPackages` where
-the interpreter and other executables are able to find each other and all of the
-modules.
-
-In the following examples we create an environment with Python 3.8, `numpy` and
-`toolz`. As you may imagine, there is one limitation here, and that's that
-you can install only one environment at a time. You will notice the complaints
-about collisions when you try to install a second environment.
-
-##### Environment defined in separate `.nix` file
-
-Create a file, e.g. `build.nix`, with the following expression
-```nix
-with import <nixpkgs> {};
+Applications on Nix are typically installed into your user profile imperatively
+using `nix-env -i`, and on NixOS declaratively by adding the package name to
+`environment.systemPackages` in `/etc/nixos/configuration.nix`. Dependencies
+such as libraries are automatically installed and should not be installed
+explicitly.
 
-python38.withPackages (ps: with ps; [ numpy toolz ])
-```
-and install it in your profile with
-```shell
-nix-env -if build.nix
-```
-Now you can use the Python interpreter, as well as the extra packages (`numpy`,
-`toolz`) that you added to the environment.
+The same goes for Python applications. Python applications can be installed in
+your profile, and will be wrapped to find their exact library dependencies,
+without impacting other applications or polluting your user environment.
 
-##### Environment defined in `~/.config/nixpkgs/config.nix`
+But Python libraries you would like to use for development cannot be installed,
+at least not individually, because they won't be able to find each other
+resulting in import errors. Instead, it is possible to create an environment
+with `python.buildEnv` or `python.withPackages` where the interpreter and other
+executables are wrapped to be able to find each other and all of the modules.
 
-If you prefer you could also add the environment as a package override to the
-Nixpkgs set, e.g. using `config.nix`,
+In the following examples we will start by creating a simple, ad-hoc environment
+with a nix-shell that has `numpy` and `toolz` in Python 3.8; then we will create
+a re-usable environment in a single-file Python script; then we will create a
+full Python environment for development with this same environment.
 
-```nix
-{ # ...
+Philosphically, this should be familiar to users who are used to a `venv` style
+of development: individual projects create their own Python environments without
+impacting the global environment or each other.
 
-  packageOverrides = pkgs: with pkgs; {
-    myEnv = python38.withPackages (ps: with ps; [ numpy toolz ]);
-  };
-}
-```
-and install it in your profile with
-
-```shell
-nix-env -iA nixpkgs.myEnv
-```
+#### Ad-hoc temporary Python environment with `nix-shell`
 
-The environment is is installed by referring to the attribute, and considering
-the `nixpkgs` channel was used.
+The simplest way to start playing with the way nix wraps and sets up Python
+environments is with `nix-shell` at the cmdline. These environments create a
+temporary shell session with a Python and a *precise* list of packages (plus
+their runtime dependencies), with no other Python packages in the Python
+interpreter's scope.
 
-##### Environment defined in `/etc/nixos/configuration.nix`
+To create a Python 3.8 session with `numpy` and `toolz` available, run:
 
-For the sake of completeness, here's another example how to install the
-environment system-wide.
+```sh
+$ nix-shell -p 'python38.withPackages(ps: with ps; [ numpy toolz ])'
+```
 
-```nix
-{ # ...
+By default `nix-shell` will start a `bash` session with this interpreter in our
+`PATH`, so if we then run:
 
-  environment.systemPackages = with pkgs; [
-    (python38.withPackages(ps: with ps; [ numpy toolz ]))
-  ];
-}
+```
+[nix-shell:~/src/nixpkgs]$ python3
+Python 3.8.1 (default, Dec 18 2019, 19:06:26)
+[GCC 9.2.0] on linux
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import numpy; import toolz
 ```
 
-#### Temporary Python environment with `nix-shell`
+Note that no other modules are in scope, even if they were imperatively
+installed into our user environment as a dependency of a Python application:
 
-The examples in the previous section showed how to install a Python environment
-into a profile. For development you may need to use multiple environments.
-`nix-shell` gives the possibility to temporarily load another environment, akin
-to `virtualenv`.
+```
+>>> import requests
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ModuleNotFoundError: No module named 'requests'
+```
 
-There are two methods for loading a shell with Python packages. The first and
-recommended method is to create an environment with `python.buildEnv` or
-`python.withPackages` and load that. E.g.
+We can add as many additional modules onto the `nix-shell` as we need, and we
+will still get 1 wrapped Python interpreter. We can start the interpreter
+directly like so:
 
 ```sh
-$ nix-shell -p 'python38.withPackages(ps: with ps; [ numpy toolz ])'
+$ nix-shell -p 'python38.withPackages(ps: with ps; [ numpy toolz requests ])' --run python3
+these derivations will be built:
+  /nix/store/xbdsrqrsfa1yva5s7pzsra8k08gxlbz1-python3-3.8.1-env.drv
+building '/nix/store/xbdsrqrsfa1yva5s7pzsra8k08gxlbz1-python3-3.8.1-env.drv'...
+created 277 symlinks in user environment
+Python 3.8.1 (default, Dec 18 2019, 19:06:26)
+[GCC 9.2.0] on linux
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import requests
+>>>
+```
+
+Notice that this time it built a new Python environment, which now includes
+`requests`. Building an environment just creates wrapper scripts that expose the
+selected dependencies to the interpreter while re-using the actual modules. This
+means if any other env has installed `requests` or `numpy` in a different
+context, we don't need to recompile them -- we just recompile the wrapper script
+that sets up an interpreter pointing to them. This matters much more for "big"
+modules like `pytorch` or `tensorflow`.
+
+Module names usually match their names on [pypi.org](https://pypi.org/), but
+you can use the [Nixpkgs search website](https://nixos.org/nixos/packages.html)
+to find them as well (along with non-python packages).
+
+At this point we can create throwaway experimental Python environments with
+arbitrary dependencies. This is a good way to get a feel for how the Python
+interpreter and dependencies work in Nix and NixOS, but to do some actual
+development, we'll want to make it a bit more persistent.
+
+##### Running Python scripts and using `nix-shell` as shebang
+
+Sometimes, we have a script whose header looks like this:
+
+```python
+#!/usr/bin/env python3
+import numpy as np
+a = np.array([1,2])
+b = np.array([3,4])
+print(f"The dot product of {a} and {b} is: {np.dot(a, b)}")
 ```
 
-opens a shell from which you can launch the interpreter
+Executing this script requires a `python3` that has `numpy`. Using what we learned
+in the previous section, we could startup a shell and just run it like so:
 
-```sh
-[nix-shell:~] python3
+```
+nix-shell -p 'python38.withPackages(ps: with ps; [ numpy ])' --run 'python3 foo.py'
+The dot product of [1 2] and [3 4] is: 11
+```
+
+But if we maintain the script ourselves, and if there are more dependencies, it
+may be nice to encode those dependencies in source to make the script re-usable
+without that bit of knowledge. That can be done by using `nix-shell` as a
+[shebang](https://en.wikipedia.org/wiki/Shebang_(Unix), like so:
+
+```python
+#!/usr/bin/env nix-shell
+#!nix-shell -i python3 -p "python3.withPackages(ps: [ ps.numpy ])"
+import numpy as np
+a = np.array([1,2])
+b = np.array([3,4])
+print(f"The dot product of {a} and {b} is: {np.dot(a, b)}")
 ```
 
-The other method, which is not recommended, does not create an environment and
-requires you to list the packages directly,
+Then we simply execute it, without requiring any environment setup at all!
 
 ```sh
-$ nix-shell -p python38.pkgs.numpy python38.pkgs.toolz
+$ ./foo.py
+The dot product of [1 2] and [3 4] is: 11
 ```
 
-Again, it is possible to launch the interpreter from the shell. The Python
-interpreter has the attribute `pkgs` which contains all Python libraries for
-that specific interpreter.
+If the dependencies are not available on the host where `foo.py` is executed, it
+will build or download them from a Nix binary cache prior to starting up, prior
+that it is executed on a machine with a multi-user nix installation.
+
+This provides a way to ship a self bootstrapping Python script, akin to a
+statically linked binary, where it can be run on any machine (provided nix is
+installed) without having to assume that `numpy` is installed globally on the
+system.
+
+By default it is pulling the import checkout of Nixpkgs itself from our nix
+channel, which is nice as it cache aligns with our other package builds, but we
+can make it fully reproducible by pinning the `nixpkgs` import:
+
+```python
+#!/usr/bin/env nix-shell
+#!nix-shell -i python3 -p "python3.withPackages(ps: [ ps.numpy ])"
+#!nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/d373d80b1207d52621961b16aa4a3438e4f98167.tar.gz
+import numpy as np
+a = np.array([1,2])
+b = np.array([3,4])
+print(f"The dot product of {a} and {b} is: {np.dot(a, b)}")
+```
+
+This will execute with the exact same versions of Python 3.8, numpy, and system
+dependencies a year from now as it does today, because it will always use
+exactly git commit `d373d80b1207d52621961b16aa4a3438e4f98167` of Nixpkgs for all
+of the package versions.
+
+This is also a great way to ensure the script executes identically on different
+servers.
 
 ##### Load environment from `.nix` expression
-As explained in the Nix manual, `nix-shell` can also load an
-expression from a `.nix` file. Say we want to have Python 3.8, `numpy`
-and `toolz`, like before, in an environment. Consider a `shell.nix` file
-with
+
+We've now seen how to create an ad-hoc temporary shell session, and how to
+create a single script with Python dependencies, but in the course of normal
+development we're usually working in an entire package repository.
+
+As explained in the Nix manual, `nix-shell` can also load an expression from a
+`.nix` file. Say we want to have Python 3.8, `numpy` and `toolz`, like before,
+in an environment. We can add a `shell.nix` file describing our dependencies:
 
 ```nix
 with import <nixpkgs> {};
-
 (python38.withPackages (ps: [ps.numpy ps.toolz])).env
 ```
 
-Executing `nix-shell` gives you again a Nix shell from which you can run Python.
+And then at the command line, just typing `nix-shell` produces the same
+environment as before. In a normal project, we'll likely have many more
+dependencies; this can provide a way for developers to share the environments
+with each other and with CI builders.
 
 What's happening here?
 
@@ -158,9 +228,9 @@ What's happening here?
    imports the `<nixpkgs>` function, `{}` calls it and the `with` statement
    brings all attributes of `nixpkgs` in the local scope. These attributes form
    the main package set.
-2. Then we create a Python 3.8 environment with the `withPackages` function.
+2. Then we create a Python 3.8 environment with the `withPackages` function, as before.
 3. The `withPackages` function expects us to provide a function as an argument
-   that takes the set of all python packages and returns a list of packages to
+   that takes the set of all Python packages and returns a list of packages to
    include in the environment. Here, we select the packages `numpy` and `toolz`
    from the package set.
 
@@ -168,7 +238,6 @@ To combine this with `mkShell` you can:
 
 ```nix
 with import <nixpkgs> {};
-
 let
   pythonEnv = python38.withPackages (ps: [
     ps.numpy
@@ -177,50 +246,98 @@ let
 in mkShell {
   buildInputs = [
     pythonEnv
-    hello
+
+    black
+    mypy
+
+    libffi
+    openssl
   ];
 }
 ```
 
-##### Execute command with `--run`
-A convenient option with `nix-shell` is the `--run`
-option, with which you can execute a command in the `nix-shell`. We can
-e.g. directly open a Python shell
+This will create a unified environment that has not just our Python interpreter
+and its Python dependencies, but also tools like `black` or `mypy` and libraries
+like `libffi` the `openssl` in scope. This is generic and can span any number of
+tools or languages across the Nixpkgs ecosystem.
 
-```sh
-$ nix-shell -p python38Packages.numpy python38Packages.toolz --run "python3"
+##### Installing environments globally on the system
+
+Up to now, we've been creating environments scoped to an ad-hoc shell session,
+or a single script, or a single project. This is generally advisable, as it
+avoids pollution across contexts.
+
+However, sometimes we know we will often want a Python with some basic packages,
+and want this available without having to enter into a shell or build context.
+This can be useful to have things like vim/emacs editors and plugins or shell
+tools "just work" without having to set them up, or when running other software
+that expects packages to be installed globally.
+
+To create your own custom environment, create a file in `~/.config/nixpkgs/overlays/`
+that looks like this:
+
+```nix
+# ~/.config/nixpkgs/overlays/myEnv.nix
+self: super: {
+  myEnv = super.buildEnv {
+    name = "myEnv";
+    paths = [
+      # A Python 3 interpreter with some packages
+      (self.python3.withPackages (
+        ps: with ps; [
+          pyflakes
+          pytest
+          python-language-server
+        ]
+      ))
+
+      # Some other packages we'd like as part of this env
+      self.mypy
+      self.black
+      self.ripgrep
+      self.tmux
+    ];
+  };
+}
 ```
 
-or run a script
+You can then build and install this to your profile with:
 
 ```sh
-$ nix-shell -p python38Packages.numpy python38Packages.toolz --run "python3 myscript.py"
+nix-env -iA myEnv
 ```
 
-##### `nix-shell` as shebang
-In fact, for the second use case, there is a more convenient method. You can add
-a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) to your script
-specifying which dependencies `nix-shell` needs. With the following shebang, you
-can just execute `./myscript.py`, and it will make available all dependencies
-and run the script in the `python3` shell.
+One limitation of this is that you can only have 1 Python env installed
+globally, since they conflict on the `python` to load out of your `PATH`.
+
+If you get a conflict or prefer to keep the setup clean, you can have `nix-env`
+atomically *uninstall* all other imperatively installed packages and replace
+your profile with just `myEnv` by using the `--replace` flag.
+
+##### Environment defined in `/etc/nixos/configuration.nix`
 
-```py
-#! /usr/bin/env nix-shell
-#! nix-shell -i python3 -p "python3.withPackages(ps: [ps.numpy])"
+For the sake of completeness, here's how to install the environment system-wide
+on NixOS.
 
-import numpy
+```nix
+{ # ...
 
-print(numpy.__version__)
+  environment.systemPackages = with pkgs; [
+    (python38.withPackages(ps: with ps; [ numpy toolz ]))
+  ];
+}
 ```
 
 ### Developing with Python
 
-Now that you know how to get a working Python environment with Nix, it is time
-to go forward and start actually developing with Python. We will first have a
-look at how Python packages are packaged on Nix. Then, we will look at how you
-can use development mode with your code.
+Above, we were mostly just focused on use cases and what to do to get started
+creating working Python environments in nix.
 
-#### Packaging a library
+Now that you know the basics to be up and running, it is time to take a step
+back and take a deeper look at at how Python packages are packaged on Nix. Then,
+we will look at how you can use development mode with your code.
+
+#### Python library packages in Nixpkgs
 
 With Nix all packages are built by functions. The main function in Nix for
 building Python libraries is `buildPythonPackage`. Let's see how we can build the
@@ -262,6 +379,7 @@ An expression for `toolz` can be found in the Nixpkgs repository. As explained
 in the introduction of this Python section, a derivation of `toolz` is available
 for each interpreter version, e.g. `python38.pkgs.toolz` refers to the `toolz`
 derivation corresponding to the CPython 3.8 interpreter.
+
 The above example works when you're directly working on
 `pkgs/top-level/python-packages.nix` in the Nixpkgs repository. Often though,
 you will want to test a Nix expression outside of the Nixpkgs tree.
@@ -312,7 +430,7 @@ Our example, `toolz`, does not have any dependencies on other Python packages or
 system libraries. According to the manual, `buildPythonPackage` uses the
 arguments `buildInputs` and `propagatedBuildInputs` to specify dependencies. If
 something is exclusively a build-time dependency, then the dependency should be
-included as a `buildInput`, but if it is (also) a runtime dependency, then it
+included in `buildInputs`, but if it is (also) a runtime dependency, then it
 should be added to `propagatedBuildInputs`. Test dependencies are considered
 build-time dependencies and passed to `checkInputs`.
 
@@ -423,10 +541,11 @@ Note also the line `doCheck = false;`, we explicitly disabled running the test-s
 
 #### Develop local package
 
-As a Python developer you're likely aware of [development mode](http://setuptools.readthedocs.io/en/latest/setuptools.html#development-mode) (`python setup.py develop`);
-instead of installing the package this command creates a special link to the project code.
-That way, you can run updated code without having to reinstall after each and every change you make.
-Development mode is also available. Let's see how you can use it.
+As a Python developer you're likely aware of [development mode](http://setuptools.readthedocs.io/en/latest/setuptools.html#development-mode)
+(`python setup.py develop`); instead of installing the package this command
+creates a special link to the project code. That way, you can run updated code
+without having to reinstall after each and every change you make. Development
+mode is also available. Let's see how you can use it.
 
 In the previous Nix expression the source was fetched from an url. We can also
 refer to a local source instead using `src = ./path/to/source/tree;`
@@ -455,7 +574,6 @@ buildPythonPackage rec {
 It is important to note that due to how development mode is implemented on Nix
 it is not possible to have multiple packages simultaneously in development mode.
 
-
 ### Organising your packages
 
 So far we discussed how you can use Python on Nix, and how you can develop with
@@ -481,11 +599,11 @@ We first create a function that builds `toolz` in `~/path/to/toolz/release.nix`
 
 buildPythonPackage rec {
   pname = "toolz";
-  version = "0.7.4";
+  version = "0.10.0";
 
   src = fetchPypi {
     inherit pname version;
-    sha256 = "43c2c9e5e7a16b6c88ba3088a9bfc82f7db8e13378be7c78d6c14a5f8ed05afd";
+    sha256 = "08fdd5ef7c96480ad11c12d472de21acd32359996f69a5259299b540feba4560";
   };
 
   meta = with lib; {
@@ -497,8 +615,8 @@ buildPythonPackage rec {
 }
 ```
 
-It takes an argument `buildPythonPackage`.
-We now call this function using `callPackage` in the definition of our environment
+It takes an argument `buildPythonPackage`. We now call this function using
+`callPackage` in the definition of our environment
 
 ```nix
 with import <nixpkgs> {};
@@ -548,7 +666,7 @@ Each interpreter has the following attributes:
 - `buildEnv`. Function to build python interpreter environments with extra packages bundled together. See section *python.buildEnv function* for usage and documentation.
 - `withPackages`. Simpler interface to `buildEnv`. See section *python.withPackages function* for usage and documentation.
 - `sitePackages`. Alias for `lib/${libPrefix}/site-packages`.
-- `executable`. Name of the interpreter executable, e.g. `python3.7`.
+- `executable`. Name of the interpreter executable, e.g. `python3.8`.
 - `pkgs`. Set of Python packages for that specific interpreter. The package set can be modified by overriding the interpreter and passing `packageOverrides`.
 
 ### Building packages and applications
@@ -643,7 +761,7 @@ following are specific to `buildPythonPackage`:
   appears more than once in dependency tree. Default is `true`.
 * `disabled` ? false: If `true`, package is not built for the particular Python
   interpreter version.
-* `dontWrapPythonPrograms ? false`: Skip wrapping of python programs.
+* `dontWrapPythonPrograms ? false`: Skip wrapping of Python programs.
 * `permitUserSite ? false`: Skip setting the `PYTHONNOUSERSITE` environment
   variable in wrapped programs.
 * `installFlags ? []`: A list of strings. Arguments to be passed to `pip
@@ -730,7 +848,7 @@ Another difference is that `buildPythonPackage` by default prefixes the names of
 the packages with the version of the interpreter. Because this is irrelevant for
 applications, the prefix is omitted.
 
-When packaging a python application with `buildPythonApplication`, it should be
+When packaging a Python application with `buildPythonApplication`, it should be
 called with `callPackage` and passed `python` or `pythonPackages` (possibly
 specifying an interpreter version), like this:
 
@@ -761,7 +879,7 @@ luigi = callPackage ../applications/networking/cluster/luigi { };
 ```
 
 Since the package is an application, a consumer doesn't need to care about
-python versions or modules, which is why they don't go in `pythonPackages`.
+Python versions or modules, which is why they don't go in `pythonPackages`.
 
 #### `toPythonApplication` function
 
@@ -875,7 +993,7 @@ thus be also written like this:
 ```nix
 with import <nixpkgs> {};
 
-(python36.withPackages (ps: [ps.numpy ps.requests])).env
+(python38.withPackages (ps: [ps.numpy ps.requests])).env
 ```
 
 In contrast to `python.buildEnv`, `python.withPackages` does not support the
@@ -932,7 +1050,7 @@ pythonPackages.buildPythonPackage {
 Running `nix-shell` with no arguments should give you the environment in which
 the package would be built with `nix-build`.
 
-Shortcut to setup environments with C headers/libraries and python packages:
+Shortcut to setup environments with C headers/libraries and Python packages:
 
 ```shell
 nix-shell -p pythonPackages.pyramid zlib libjpeg git
@@ -963,7 +1081,6 @@ have timestamp 1. The `buildPythonPackage` function sets `DETERMINISTIC_BUILD=1`
 and [PYTHONHASHSEED=0](https://docs.python.org/3.8/using/cmdline.html#envvar-PYTHONHASHSEED).
 Both are also exported in `nix-shell`.
 
-
 ### Automatic tests
 
 It is recommended to test packages as part of the build process.
@@ -976,7 +1093,7 @@ example of such a situation is when `py.test` is used.
 #### Common issues
 
 * Non-working tests can often be deselected. By default `buildPythonPackage`
-  runs `python setup.py test`. Most python modules follows the standard test
+  runs `python setup.py test`. Most Python modules follows the standard test
   protocol where the pytest runner can be used instead. `py.test` supports a
   `-k` parameter to ignore test methods or classes:
 
@@ -1052,7 +1169,7 @@ let
   newpkgs = import pkgs.path { overlays = [ (self: super: {
     python38 = let
       packageOverrides = python-self: python-super: {
-        numpy = python-super.numpy_1_18.3;
+        numpy = python-super.numpy_1_18;
       };
     in super.python38.override {inherit packageOverrides;};
   } ) ]; };
@@ -1127,14 +1244,14 @@ If you want to create a Python environment for development, then the recommended
 method is to use `nix-shell`, either with or without the `python.buildEnv`
 function.
 
-### How to consume python modules using pip in a virtual environment like I am used to on other Operating Systems?
+### How to consume Python modules using pip in a virtual environment like I am used to on other Operating Systems?
 
 While this approach is not very idiomatic from Nix perspective, it can still be
 useful when dealing with pre-existing projects or in situations where it's not
 feasible or desired to write derivations for all required dependencies.
 
 This is an example of a `default.nix` for a `nix-shell`, which allows to consume
-a virtual environment created by `venv`, and install python modules through
+a virtual environment created by `venv`, and install Python modules through
 `pip` the traditional way.
 
 Create this `default.nix` file, together with a `requirements.txt` and simply
@@ -1149,7 +1266,7 @@ in pkgs.mkShell rec {
   name = "impurePythonEnv";
   venvDir = "./.venv";
   buildInputs = [
-    # A python interpreter including the 'venv' module is required to bootstrap
+    # A Python interpreter including the 'venv' module is required to bootstrap
     # the environment.
     pythonPackages.python
 
@@ -1163,7 +1280,7 @@ in pkgs.mkShell rec {
     pythonPackages.requests
 
     # In this particular example, in order to compile any binary extensions they may
-    # require, the python modules listed in the hypothetical requirements.txt need
+    # require, the Python modules listed in the hypothetical requirements.txt need
     # the following packages to be installed locally:
     taglib
     openssl
@@ -1183,7 +1300,7 @@ in pkgs.mkShell rec {
 }
 ```
 
-In case the supplied venvShellHook is insufficient, or when python 2 support is
+In case the supplied venvShellHook is insufficient, or when Python 2 support is
 needed, you can define your own shell hook and adapt to your needs like in the
 following example:
 
@@ -1229,7 +1346,7 @@ in pkgs.mkShell rec {
 ```
 
 Note that the `pip install` is an imperative action. So every time `nix-shell`
-is executed it will attempt to download the python modules listed in
+is executed it will attempt to download the Python modules listed in
 requirements.txt. However these will be cached locally within the `virtualenv`
 folder and not downloaded again.
 
@@ -1290,9 +1407,8 @@ self: super: {
 
 ### How to use Intel's MKL with numpy and scipy?
 
-MKL can be configured using an overlay. See the section “[Using
-overlays to configure
-alternatives](#sec-overlays-alternatives-blas-lapack)”.
+MKL can be configured using an overlay. See the section "[Using overlays to
+configure alternatives](#sec-overlays-alternatives-blas-lapack)".
 
 ### What inputs do `setup_requires`, `install_requires` and `tests_require` map to?