Bump min python version to 3.10 (#1743)

This gives use the `text=True` alias in the subprocess API, which
was already being used in some places here.

We also get access to `subprocess.run` which was added in 3.5.

We also get ordered dictionaries by default.

Also, update the min version of python mentioned in the README.md,
which refers the minimum version required by emcc, not emsdk.py,
although they happen to match for now.
diff --git a/README.md b/README.md
index c77020f..bd77510 100644
--- a/README.md
+++ b/README.md
@@ -64,7 +64,7 @@
 
 ### Linux
 
-- `python`: Version 3.8 or above.
+- `python`: Version 3.10 or above.
 - `java`: For running closure compiler (optional)
 
 The emsdk pre-compiled binaries are built against debian/stretch (for x86_64)
diff --git a/emsdk.py b/emsdk.py
index 5083785..d74e2d4 100644
--- a/emsdk.py
+++ b/emsdk.py
@@ -19,7 +19,6 @@
 import sysconfig
 import tarfile
 import zipfile
-from collections import OrderedDict
 
 if os.name == 'nt':
   import ctypes.wintypes
@@ -28,8 +27,8 @@
 from urllib.parse import urljoin
 from urllib.request import urlopen
 
-if sys.version_info < (3, 2):  # noqa: UP036
-  print(f'error: emsdk requires python 3.2 or above ({sys.executable} {sys.version})', file=sys.stderr)
+if sys.version_info < (3, 10):  # noqa: UP036
+  print(f'error: emsdk requires python 3.10 or above ({sys.executable} {sys.version})', file=sys.stderr)
   sys.exit(1)
 
 emsdk_packages_url = 'https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/'
@@ -733,7 +732,7 @@
 
 def run_get_output(cmd, cwd=None):
   debug_print(f'run_get_output(cmd={cmd}, cwd={cwd})')
-  return subprocess.check_output(cmd, cwd=cwd, universal_newlines=True)
+  return subprocess.check_output(cmd, cwd=cwd, text=True)
 
 
 def GIT():
@@ -1030,7 +1029,7 @@
 
 def xcode_sdk_version():
   try:
-    output = subprocess.check_output(['xcrun', '--show-sdk-version'], universal_newlines=True)
+    output = subprocess.check_output(['xcrun', '--show-sdk-version'], text=True)
     return output.strip().split('.')
   except Exception:
     return subprocess.checkplatform.mac_ver()[0].split('.')
@@ -1437,8 +1436,7 @@
   try:
     subprocess.check_output(
         [npm, 'ci', '--production'],
-        cwd=directory, stderr=subprocess.STDOUT, env=env,
-        universal_newlines=True)
+        cwd=directory, stderr=subprocess.STDOUT, env=env, text=True)
   except subprocess.CalledProcessError as e:
     errlog('Error running %s:\n%s' % (e.cmd, e.output))
     return False
@@ -1469,8 +1467,7 @@
       return False
     try:
       subprocess.check_output([sys.executable, os.path.join(directory, 'bootstrap.py')],
-                              cwd=directory, stderr=subprocess.STDOUT, env=env,
-                              universal_newlines=True)
+                              cwd=directory, stderr=subprocess.STDOUT, env=env, text=True)
     except subprocess.CalledProcessError as e:
       errlog('Error running %s:\n%s' % (e.cmd, e.output))
       return False
@@ -1746,10 +1743,9 @@
 
   # Different tools may provide the same activated configs; the latest to be
   # activated is the relevant one.
-  activated_config = OrderedDict()
+  activated_config = {}
   for tool in active_tools:
-    for name, value in tool.activated_config().items():
-      activated_config[name] = value
+    activated_config.update(tool.activated_config())
 
   if 'NODE_JS' not in activated_config:
     node_fallback = shutil.which('nodejs')
@@ -1919,7 +1915,7 @@
     if not self.activated_cfg:
       return {}
 
-    config = OrderedDict()
+    config = {}
     expanded = to_unix_path(self.expand_vars(self.activated_cfg))
     for specific_cfg in expanded.split(';'):
       name, value = specific_cfg.split('=')
diff --git a/pyproject.toml b/pyproject.toml
index 94cfdcb..91cb738 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [project]
 name = 'emsdk'
-requires-python = ">=3.2"
+requires-python = ">=3.10"
 
 [tool.ruff]
 preview = true