Get matplotlib working with upstream Python

This patch adds support for using matplotlib plus its Gtk backend with
`--config=k8_upstream_python`. Unfortunately, the Tk backend doesn't
work because of how Python is packaged. See the following issue for
more information:
https://github.com/matplotlib/matplotlib/issues/23074

Separately, we need to patch pygobject and matplotlib for various
hermeticity reasons. To accomplish this, I've added patching support
for wheels downloaded via rules_python. I should have set it up to use
annotations (the same mechanism we use for injecting deps), but it was
a little cumbersome. Annotations are not set up for using in arguments
to repository rules. I instead opted for a separate JSON file. You can
find it at `tools/python/patches.json`.

You can try the two new example programs:

    $ bazel run --config=k8_upstream_python //build_tests:matplotlib_example
    $ bazel run --config=k8_upstream_python //build_tests:pygobject_example

Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
Change-Id: I3c4e8648a8012aa23dedd53610e82d590d1c409d
diff --git a/build_tests/BUILD b/build_tests/BUILD
index 7c88992..718e817 100644
--- a/build_tests/BUILD
+++ b/build_tests/BUILD
@@ -232,3 +232,20 @@
         "@pip//scipy",
     ],
 )
+
+py_binary(
+    name = "pygobject_example",
+    srcs = ["pygobject_example.py"],
+    deps = [
+        "@pip//pygobject",
+    ],
+)
+
+py_binary(
+    name = "matplotlib_example",
+    srcs = ["matplotlib_example.py"],
+    deps = [
+        "@pip//matplotlib",
+        "@pip//pygobject",
+    ],
+)
diff --git a/build_tests/matplotlib_example.py b/build_tests/matplotlib_example.py
new file mode 100644
index 0000000..1331a20
--- /dev/null
+++ b/build_tests/matplotlib_example.py
@@ -0,0 +1,12 @@
+# This is the introductory example from
+# https://matplotlib.org/stable/tutorials/introductory/pyplot.html
+
+import matplotlib
+import matplotlib.pyplot as plt
+
+# Set up the gtk backend before running matplotlib.
+matplotlib.use("GTK3Agg")
+
+plt.plot([1, 2, 3, 4])
+plt.ylabel("some numbers")
+plt.show()
diff --git a/build_tests/pygobject_example.py b/build_tests/pygobject_example.py
new file mode 100644
index 0000000..c8e0bbd
--- /dev/null
+++ b/build_tests/pygobject_example.py
@@ -0,0 +1,26 @@
+# This is the extended example from
+# https://python-gtk-3-tutorial.readthedocs.io/en/latest/introduction.html#extended-example
+
+import gi
+
+gi.require_version("Gtk", "3.0")
+from gi.repository import Gtk
+
+
+class MyWindow(Gtk.Window):
+
+    def __init__(self):
+        super().__init__(title="Hello World")
+
+        self.button = Gtk.Button(label="Click Here")
+        self.button.connect("clicked", self.on_button_clicked)
+        self.add(self.button)
+
+    def on_button_clicked(self, widget):
+        print("Hello World")
+
+
+win = MyWindow()
+win.connect("destroy", Gtk.main_quit)
+win.show_all()
+Gtk.main()