Merge branch 'main' into avm99963-monorail

Merged commit 34d8229ae2b51fb1a15bd208e6fe6185c94f6266

GitOrigin-RevId: 7ee0917f93a577e475f8e09526dd144d245593f4
diff --git a/import_utils.py b/import_utils.py
new file mode 100644
index 0000000..bf8a265
--- /dev/null
+++ b/import_utils.py
@@ -0,0 +1,129 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Adds third_party packages to their respective package namespaces."""
+
+import os
+import six
+import sys
+
+
+def FixImports():
+  """Adds third_party packages to their respective package namespaces."""
+  _AddThirdPartyToPath()
+  _FixProtorpcPackage()
+  _FixDefaultApiStub()
+  _ImportProtocolBuffer()
+  _FixMox3()
+
+
+def _AddThirdPartyToPath():
+  """Adds third_party/ to sys.path.
+
+  This lets us find endpoints."""
+  sys.path.append(_ThirdPartyDir())
+
+
+def _FixProtorpcPackage():
+  """Adds third_party/protorpc/ to protorpc.__path__.
+
+  protorpc generally supports Python 3, except for a few minor issues. protorpc
+  has been unmaintained and archived for years, and will not take pull requests.
+  So, we have a local copy of a few of the files with Python 3 modifications,
+  and update the package __path__ to use our local copy.
+  """
+  import protorpc
+  package_path = os.path.join(_ThirdPartyDir(), 'protorpc')
+  protorpc.__path__.insert(0, package_path)
+
+
+def _FixDefaultApiStub():
+  """Fixes "Attempted RPC call without active security ticket" error.
+
+  In appengine-python-standard==1.0.0, default_api_stub throws an error when
+  trying to access NDB outside of a Flask request. This was fixed in commit
+  cc19a2e on Juy 21, 2022, but wasn't included in the 1.0.1rc1 release on
+  Sep 6, 2022. It's been months since that release, so instead of waiting on
+  another release, we'll just monkeypatch the file here.
+  """
+  if not six.PY3:
+    return
+  sys.path.append(os.path.join(_ThirdPartyDir(), 'appengine-python-standard'))
+  import default_api_stub as fixed_default_api_stub
+  from google.appengine.runtime import default_api_stub
+  default_api_stub.DefaultApiRPC = fixed_default_api_stub.DefaultApiRPC
+
+
+def _ImportProtocolBuffer():
+  """Adds google.net.proto.ProtocolBuffer to the importable packages.
+
+  The appengine-python-standard package doesn't include
+  google.net.proto.ProtocolBuffer. So, we include a local copy in
+  third_party/, and modify the package __path__ to use our local copy.
+  """
+  # Add third_party/google/ to the google namespace.
+  # This makes Python look in this additional location for google.net.proto.
+  import google
+  package_path = os.path.join(_ThirdPartyDir(), 'google')
+  google.__path__.append(package_path)
+
+
+def _FixMox3():
+  """Fixes a Python 3 warning with the mox3 library.
+
+  mox3 uses `inspect.getargspec()`, which is deprecated since Python 3.0.
+  This throws a warning when running unit tests. Update the method to use
+  `inspect.getfullargspec()` instead.
+  """
+  from mox3 import mox
+  mox.MethodSignatureChecker.__init__ = _MethodSignatureChecker
+
+
+def _ThirdPartyDir():
+  return os.path.join(os.path.dirname(__file__), 'third_party')
+
+
+def _MethodSignatureChecker(self, method, class_to_bind=None):
+  """Creates a checker.
+
+  Args:
+      # method: A method to check.
+      # class_to_bind: optionally, a class used to type check first
+      #                method parameter, only used with unbound methods
+      method: function
+      class_to_bind: type or None
+
+  Raises:
+      ValueError: method could not be inspected, so checks aren't
+                  possible. Some methods and functions like built-ins
+                  can't be inspected.
+  """
+  import inspect
+  try:
+    self._args, varargs, varkw, defaults, _, _, _ = inspect.getfullargspec(
+        method)
+  except TypeError:
+    raise ValueError('Could not get argument specification for %r' % (method,))
+  if (inspect.ismethod(method) or class_to_bind or
+      (hasattr(self, '_args') and len(self._args) > 0 and
+       self._args[0] == 'self')):
+    self._args = self._args[1:]  # Skip 'self'.
+  self._method = method
+  self._instance = None  # May contain the instance this is bound to.
+  self._instance = getattr(method, "__self__", None)
+
+  # _bounded_to determines whether the method is bound or not
+  if self._instance:
+    self._bounded_to = self._instance.__class__
+  else:
+    self._bounded_to = class_to_bind or getattr(method, "im_class", None)
+
+  self._has_varargs = varargs is not None
+  self._has_varkw = varkw is not None
+  if defaults is None:
+    self._required_args = self._args
+    self._default_args = []
+  else:
+    self._required_args = self._args[:-len(defaults)]
+    self._default_args = self._args[-len(defaults):]