Clean up some references to older Python versions

* Remove comments about Python 2
* Consistently use the arg `subprocess.Popen(text=...)`, also use `subprocess.Popen(encoding=...)` in one applicable place
* Drop some code supporting Python < 3.8

PiperOrigin-RevId: 766642814
diff --git a/absl/logging/__init__.py b/absl/logging/__init__.py
index df6669f..b0920d8 100644
--- a/absl/logging/__init__.py
+++ b/absl/logging/__init__.py
@@ -721,23 +721,21 @@
   """Computes the directory and filename prefix for log file.
 
   Args:
-    program_name: str|None, the filename part of the path to the program that
-        is running without its extension.  e.g: if your program is called
-        ``usr/bin/foobar.py`` this method should probably be called with
-        ``program_name='foobar`` However, this is just a convention, you can
-        pass in any string you want, and it will be used as part of the
-        log filename. If you don't pass in anything, the default behavior
-        is as described in the example.  In python standard logging mode,
-        the program_name will be prepended with ``py_`` if it is the
-        ``program_name`` argument is omitted.
+    program_name: str|None, the filename part of the path to the program that is
+      running without its extension.  e.g: if your program is called
+      ``usr/bin/foobar.py`` this method should probably be called with
+      ``program_name='foobar`` However, this is just a convention, you can pass
+      in any string you want, and it will be used as part of the log filename.
+      If you don't pass in anything, the default behavior is as described in the
+      example.  In python standard logging mode, the program_name will be
+      prepended with ``py_`` if it is the ``program_name`` argument is omitted.
     log_dir: str|None, the desired log directory.
 
   Returns:
     (log_dir, file_prefix, symlink_prefix)
 
   Raises:
-    FileNotFoundError: raised in Python 3 when it cannot find a log directory.
-    OSError: raised in Python 2 when it cannot find a log directory.
+    FileNotFoundError: raised when it cannot find a log directory.
   """
   if not program_name:
     # Strip the extension (foobar.par becomes foobar, and
@@ -771,13 +769,12 @@
 
   Args:
     log_dir: str|None, if specified, the logfile(s) will be created in that
-        directory.  Otherwise if the --log_dir command-line flag is provided,
-        the logfile will be created in that directory.  Otherwise the logfile
-        will be created in a standard location.
+      directory.  Otherwise if the --log_dir command-line flag is provided, the
+      logfile will be created in that directory.  Otherwise the logfile will be
+      created in a standard location.
 
   Raises:
-    FileNotFoundError: raised in Python 3 when it cannot find a log directory.
-    OSError: raised in Python 2 when it cannot find a log directory.
+    FileNotFoundError: raised when it cannot find a log directory.
   """
   # Get a list of possible log dirs (will try to use them in order).
   # NOTE: Google's internal implementation has a special handling for Google
diff --git a/absl/logging/__init__.pyi b/absl/logging/__init__.pyi
index b14af03..8b625a7 100644
--- a/absl/logging/__init__.pyi
+++ b/absl/logging/__init__.pyi
@@ -35,54 +35,42 @@
 STDERRTHRESHOLD: flags.FlagHolder[str]
 SHOWPREFIXFORINFO: flags.FlagHolder[bool]
 
-
 def get_verbosity() -> int:
   ...
 
-
 def set_verbosity(v: Union[int, str]) -> None:
   ...
 
-
 def set_stderrthreshold(s: Union[int, str]) -> None:
   ...
 
-
 # TODO(b/277607978): Provide actual args+kwargs shadowing stdlib's logging functions.
 def fatal(msg: Any, *args: Any, **kwargs: Any) -> NoReturn:
   ...
 
-
 def error(msg: Any, *args: Any, **kwargs: Any) -> None:
   ...
 
-
 def warning(msg: Any, *args: Any, **kwargs: Any) -> None:
   ...
 
-
 def warn(msg: Any, *args: Any, **kwargs: Any) -> None:
   ...
 
-
 def info(msg: Any, *args: Any, **kwargs: Any) -> None:
   ...
 
-
 def debug(msg: Any, *args: Any, **kwargs: Any) -> None:
   ...
 
-
 def exception(msg: Any, *args: Any, **kwargs: Any) -> None:
   ...
 
-
 def log_every_n(
     level: int, msg: Any, n: int, *args: Any, use_call_stack: bool = ...
 ) -> None:
   ...
 
-
 def log_every_n_seconds(
     level: int,
     msg: Any,
@@ -92,79 +80,61 @@
 ) -> None:
   ...
 
-
 def log_first_n(
     level: int, msg: Any, n: int, *args: Any, use_call_stack: bool = ...
 ) -> None:
   ...
 
-
 def log_if(level: int, msg: Any, condition: Any, *args: Any) -> None:
   ...
 
-
 def log(level: int, msg: Any, *args: Any, **kwargs: Any) -> None:
   ...
 
-
 def vlog(level: int, msg: Any, *args: Any, **kwargs: Any) -> None:
   ...
 
-
 def vlog_is_on(level: int) -> bool:
   ...
 
-
 def flush() -> None:
   ...
 
-
 def level_debug() -> bool:
   ...
 
-
 def level_info() -> bool:
   ...
 
-
 def level_warning() -> bool:
   ...
 
-
 level_warn = level_warning  # Deprecated function.
 
-
 def level_error() -> bool:
   ...
 
-
 def get_log_file_name(level: int = ...) -> str:
   ...
 
-
 def find_log_dir_and_names(
     program_name: Optional[str] = ..., log_dir: Optional[str] = ...
 ) -> Tuple[str, str, str]:
   ...
 
-
 def find_log_dir(log_dir: Optional[str] = ...) -> str:
   ...
 
-
 def get_absl_log_prefix(record: logging.LogRecord) -> str:
   ...
 
-
 _SkipLogT = TypeVar('_SkipLogT', str, Callable[..., Any])
 
 def skip_log_prefix(func: _SkipLogT) -> _SkipLogT:
   ...
 
-
 _StreamT = TypeVar('_StreamT')
 
-
 class PythonHandler(logging.StreamHandler[_StreamT]):  # type: ignore[type-var]
 
   def __init__(
@@ -193,7 +163,6 @@
   def close(self) -> None:
     ...
 
-
 class ABSLHandler(logging.Handler):
 
   def __init__(self, python_logging_formatter: PythonFormatter) -> None:
@@ -232,13 +201,11 @@
   def start_logging_to_file(self, program_name=None, log_dir=None) -> None:
     ...
 
-
 class PythonFormatter(logging.Formatter):
 
   def format(self, record: logging.LogRecord) -> str:
     ...
 
-
 class ABSLLogger(logging.Logger):
 
   def findCaller(
@@ -279,20 +246,16 @@
   ) -> None:
     ...
 
-
 # NOTE: Returns None before _initialize called but shouldn't occur after import.
 def get_absl_logger() -> ABSLLogger:
   ...
 
-
 # NOTE: Returns None before _initialize called but shouldn't occur after import.
 def get_absl_handler() -> ABSLHandler:
   ...
 
-
 def use_python_logging(quiet: bool = ...) -> None:
   ...
 
-
 def use_absl_handler() -> None:
   ...
diff --git a/absl/logging/tests/logging_functional_test.py b/absl/logging/tests/logging_functional_test.py
index 4148809..af5da91 100644
--- a/absl/logging/tests/logging_functional_test.py
+++ b/absl/logging/tests/logging_functional_test.py
@@ -388,8 +388,12 @@
     print('env: %s' % env, file=sys.stderr)
     print('cmd: %s' % cmd, file=sys.stderr)
     process = subprocess.Popen(
-        cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env,
-        universal_newlines=True)
+        cmd,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.STDOUT,
+        env=env,
+        text=True,
+    )
     output, _ = process.communicate()
     status = process.returncode
 
diff --git a/absl/testing/absltest.py b/absl/testing/absltest.py
index 81d5267..8831b69 100644
--- a/absl/testing/absltest.py
+++ b/absl/testing/absltest.py
@@ -278,9 +278,8 @@
 
   Creation of this class is internal. Using its public methods is OK.
 
-  This class implements the `os.PathLike` interface (specifically,
-  `os.PathLike[str]`). This means, in Python 3, it can be directly passed
-  to e.g. `os.path.join()`.
+  This class implements the `os.PathLike[str]` interface. This means it can
+  be directly passed to e.g. `os.path.join()`.
   """
 
   def __init__(self, path: str) -> None:
@@ -361,9 +360,8 @@
 
   Creation of this class is internal. Using its public methods is OK.
 
-  This class implements the `os.PathLike` interface (specifically,
-  `os.PathLike[str]`). This means, in Python 3, it can be directly passed
-  to e.g. `os.path.join()`.
+  This class implements the `os.PathLike[str]` interface. This means it can
+  be directly passed to e.g. `os.path.join()`.
   """
 
   def __init__(self, path: str) -> None:
@@ -443,9 +441,7 @@
     """Write text to the file.
 
     Args:
-      text: Text to write. In Python 2, it can be bytes, which will be
-        decoded using the `encoding` arg (this is as an aid for code that
-        is 2 and 3 compatible).
+      text: Text to write.
       mode: The mode to open the file for writing.
       encoding: The encoding to use when writing the text to the file.
       errors: The error handling strategy to use when converting text to bytes.
diff --git a/absl/testing/tests/absltest_fail_fast_test.py b/absl/testing/tests/absltest_fail_fast_test.py
index efde8a0..8e3fb68 100644
--- a/absl/testing/tests/absltest_fail_fast_test.py
+++ b/absl/testing/tests/absltest_fail_fast_test.py
@@ -58,7 +58,8 @@
         env=env,
         stdout=subprocess.PIPE,
         stderr=subprocess.STDOUT,
-        universal_newlines=True)
+        text=True,
+    )
     stdout = proc.communicate()[0]
 
     logging.info('output: %s', stdout)
diff --git a/absl/testing/tests/absltest_filtering_test.py b/absl/testing/tests/absltest_filtering_test.py
index a098745..346001d 100644
--- a/absl/testing/tests/absltest_filtering_test.py
+++ b/absl/testing/tests/absltest_filtering_test.py
@@ -65,12 +65,15 @@
         additional_args.extend(['-k=' + f for f in test_filter.split(' ')])
 
     proc = subprocess.Popen(
-        args=([_bazelize_command.get_executable_path(self._test_name)] +
-              additional_args),
+        args=(
+            [_bazelize_command.get_executable_path(self._test_name)]
+            + additional_args
+        ),
         env=env,
         stdout=subprocess.PIPE,
         stderr=subprocess.STDOUT,
-        universal_newlines=True)
+        text=True,
+    )
     stdout = proc.communicate()[0]
 
     logging.info('output: %s', stdout)
diff --git a/absl/testing/tests/absltest_randomization_test.py b/absl/testing/tests/absltest_randomization_test.py
index 7150be8..f25a31a 100644
--- a/absl/testing/tests/absltest_randomization_test.py
+++ b/absl/testing/tests/absltest_randomization_test.py
@@ -60,7 +60,8 @@
         env=env,
         stdout=subprocess.PIPE,
         stderr=subprocess.STDOUT,
-        universal_newlines=True)
+        text=True,
+    )
 
     stdout, _ = proc.communicate()
 
diff --git a/absl/testing/tests/absltest_sharding_test.py b/absl/testing/tests/absltest_sharding_test.py
index cd4434a..0f2de21 100644
--- a/absl/testing/tests/absltest_sharding_test.py
+++ b/absl/testing/tests/absltest_sharding_test.py
@@ -83,7 +83,7 @@
         env=env,
         stdout=subprocess.PIPE,
         stderr=subprocess.STDOUT,
-        universal_newlines=True,
+        text=True,
     )
     stdout = proc.communicate()[0]
 
diff --git a/absl/testing/tests/absltest_test.py b/absl/testing/tests/absltest_test.py
index 684bbc4..fb315ad 100644
--- a/absl/testing/tests/absltest_test.py
+++ b/absl/testing/tests/absltest_test.py
@@ -80,8 +80,12 @@
       command.append(f'--test_id={test_id}')
     command.extend(args)
     process = subprocess.Popen(
-        command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env,
-        universal_newlines=True)
+        command,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        env=env,
+        text=True,
+    )
     stdout, stderr = process.communicate()
     if expect_success:
       self.assertEqual(
diff --git a/absl/tests/app_test.py b/absl/tests/app_test.py
index 5c79417..71c5255 100644
--- a/absl/tests/app_test.py
+++ b/absl/tests/app_test.py
@@ -47,10 +47,6 @@
   sys.modules['__main__'].__doc__ = old_doc
 
 
-def _normalize_newlines(s):
-  return re.sub('(\r\n)|\r', '\n', s)
-
-
 class UnitTests(absltest.TestCase):
 
   def test_install_exception_handler(self):
@@ -141,13 +137,12 @@
     process = subprocess.Popen(
         [_bazelize_command.get_executable_path(helper)] + list(arguments),
         stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE, env=env, universal_newlines=False)
+        stderr=subprocess.PIPE,
+        env=env,
+        text=True,
+        encoding='utf8',
+    )
     stdout, stderr = process.communicate()
-    # In Python 2, we can't control the encoding used by universal_newline
-    # mode, which can cause UnicodeDecodeErrors when subprocess tries to
-    # convert the bytes to unicode, so we have to decode it manually.
-    stdout = _normalize_newlines(stdout.decode('utf8'))
-    stderr = _normalize_newlines(stderr.decode('utf8'))
 
     message = (
         'Command: {command}\n'