pw_protobuf: Install graphlib-backport for Python 3.8

Also remove argparse.BooleanOptionalAction from bloaty config as it is
Python 3.9 only.

Bug: b/229257942

Change-Id: I9240d8e2ca4c44abb241cbf1b49b3722278a3af9
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/91160
Reviewed-by: Scott James Remnant <keybuk@google.com>
Commit-Queue: Anthony DiGirolamo <tonymd@google.com>
diff --git a/pw_bloat/py/pw_bloat/bloaty_config.py b/pw_bloat/py/pw_bloat/bloaty_config.py
index d5a38dc..68e924a 100644
--- a/pw_bloat/py/pw_bloat/bloaty_config.py
+++ b/pw_bloat/py/pw_bloat/bloaty_config.py
@@ -44,19 +44,33 @@
                         default=sys.stdout)
     parser.add_argument(
         '--utilization',
-        action=argparse.BooleanOptionalAction,
+        action='store_true',
+        dest='utilization',
         default=True,
-        help=(
-            'Generate the utilization custom_data_source based on sections ' +
-            'with "unused_space" in anywhere in their name'))
+        help=('Generate the utilization custom_data_source based on sections '
+              'with "unused_space" in anywhere in their name'),
+    )
+    parser.add_argument(
+        '--no-utilization',
+        action='store_false',
+        dest='utilization',
+    )
+
     parser.add_argument(
         '--memoryregions',
-        action=argparse.BooleanOptionalAction,
+        action='store_true',
         default=True,
-        help=('Generate the memoryregions custom_data_source based on ' +
-              'symbols defined in the linker script matching the following ' +
-              'pattern: ' +
-              '"pw::bloat::config::memory_region::NAME[0].{start,end}"'))
+        help=('Generate the memoryregions custom_data_source based on '
+              'symbols defined in the linker script matching the following '
+              'pattern: '
+              '"pw::bloat::config::memory_region::NAME[0].{start,end}"'),
+    )
+    parser.add_argument(
+        '--no-memoryregions',
+        action='store_false',
+        dest='memoryregions',
+    )
+
     parser.add_argument('-l',
                         '--loglevel',
                         type=pw_cli.argument_types.log_level,
diff --git a/pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list b/pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list
index 5cf370a..84f30a2 100644
--- a/pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list
+++ b/pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list
@@ -23,6 +23,7 @@
 google-crc32c==1.3.0
 google-resumable-media==2.3.2
 googleapis-common-protos==1.56.0
+graphlib-backport==1.0.3;python_version<'3.9'
 grpcio==1.43.0
 grpcio-tools==1.43.0
 httpwatcher==0.5.2
diff --git a/pw_protobuf/py/pw_protobuf/codegen_pwpb.py b/pw_protobuf/py/pw_protobuf/codegen_pwpb.py
index df4fcc5..bb09027 100644
--- a/pw_protobuf/py/pw_protobuf/codegen_pwpb.py
+++ b/pw_protobuf/py/pw_protobuf/codegen_pwpb.py
@@ -16,7 +16,8 @@
 import abc
 from datetime import datetime
 import enum
-from graphlib import CycleError, TopologicalSorter
+# Type ignore here for graphlib-backport on Python 3.8
+from graphlib import CycleError, TopologicalSorter  # type: ignore
 import os
 import sys
 from typing import Dict, Iterable, List, Tuple
diff --git a/pw_protobuf/py/setup.cfg b/pw_protobuf/py/setup.cfg
index d4bc72f..a2bbc18 100644
--- a/pw_protobuf/py/setup.cfg
+++ b/pw_protobuf/py/setup.cfg
@@ -21,7 +21,10 @@
 [options]
 packages = find:
 zip_safe = False
-install_requires = protobuf; pw_cli
+install_requires =
+    protobuf
+    pw_cli
+    graphlib-backport;python_version<'3.9'
 
 [options.entry_points]
 console_scripts =