Adrià Vilanova MartÃnez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 1 | # Copyright 2023 The Chromium Authors |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
| 5 | """Adds third_party packages to their respective package namespaces.""" |
| 6 | |
| 7 | import os |
| 8 | import six |
| 9 | import sys |
| 10 | |
| 11 | |
| 12 | def FixImports(): |
| 13 | """Adds third_party packages to their respective package namespaces.""" |
| 14 | _AddThirdPartyToPath() |
| 15 | _FixProtorpcPackage() |
| 16 | _FixDefaultApiStub() |
| 17 | _ImportProtocolBuffer() |
| 18 | _FixMox3() |
| 19 | |
| 20 | |
| 21 | def _AddThirdPartyToPath(): |
| 22 | """Adds third_party/ to sys.path. |
| 23 | |
| 24 | This lets us find endpoints.""" |
| 25 | sys.path.append(_ThirdPartyDir()) |
| 26 | |
| 27 | |
| 28 | def _FixProtorpcPackage(): |
| 29 | """Adds third_party/protorpc/ to protorpc.__path__. |
| 30 | |
| 31 | protorpc generally supports Python 3, except for a few minor issues. protorpc |
| 32 | has been unmaintained and archived for years, and will not take pull requests. |
| 33 | So, we have a local copy of a few of the files with Python 3 modifications, |
| 34 | and update the package __path__ to use our local copy. |
| 35 | """ |
| 36 | import protorpc |
| 37 | package_path = os.path.join(_ThirdPartyDir(), 'protorpc') |
| 38 | protorpc.__path__.insert(0, package_path) |
| 39 | |
| 40 | |
| 41 | def _FixDefaultApiStub(): |
| 42 | """Fixes "Attempted RPC call without active security ticket" error. |
| 43 | |
| 44 | In appengine-python-standard==1.0.0, default_api_stub throws an error when |
| 45 | trying to access NDB outside of a Flask request. This was fixed in commit |
| 46 | cc19a2e on Juy 21, 2022, but wasn't included in the 1.0.1rc1 release on |
| 47 | Sep 6, 2022. It's been months since that release, so instead of waiting on |
| 48 | another release, we'll just monkeypatch the file here. |
| 49 | """ |
| 50 | if not six.PY3: |
| 51 | return |
| 52 | sys.path.append(os.path.join(_ThirdPartyDir(), 'appengine-python-standard')) |
| 53 | import default_api_stub as fixed_default_api_stub |
| 54 | from google.appengine.runtime import default_api_stub |
| 55 | default_api_stub.DefaultApiRPC = fixed_default_api_stub.DefaultApiRPC |
| 56 | |
| 57 | |
| 58 | def _ImportProtocolBuffer(): |
| 59 | """Adds google.net.proto.ProtocolBuffer to the importable packages. |
| 60 | |
| 61 | The appengine-python-standard package doesn't include |
| 62 | google.net.proto.ProtocolBuffer. So, we include a local copy in |
| 63 | third_party/, and modify the package __path__ to use our local copy. |
| 64 | """ |
| 65 | # Add third_party/google/ to the google namespace. |
| 66 | # This makes Python look in this additional location for google.net.proto. |
| 67 | import google |
| 68 | package_path = os.path.join(_ThirdPartyDir(), 'google') |
| 69 | google.__path__.append(package_path) |
| 70 | |
| 71 | |
| 72 | def _FixMox3(): |
| 73 | """Fixes a Python 3 warning with the mox3 library. |
| 74 | |
| 75 | mox3 uses `inspect.getargspec()`, which is deprecated since Python 3.0. |
| 76 | This throws a warning when running unit tests. Update the method to use |
| 77 | `inspect.getfullargspec()` instead. |
| 78 | """ |
| 79 | from mox3 import mox |
| 80 | mox.MethodSignatureChecker.__init__ = _MethodSignatureChecker |
| 81 | |
| 82 | |
| 83 | def _ThirdPartyDir(): |
| 84 | return os.path.join(os.path.dirname(__file__), 'third_party') |
| 85 | |
| 86 | |
| 87 | def _MethodSignatureChecker(self, method, class_to_bind=None): |
| 88 | """Creates a checker. |
| 89 | |
| 90 | Args: |
| 91 | # method: A method to check. |
| 92 | # class_to_bind: optionally, a class used to type check first |
| 93 | # method parameter, only used with unbound methods |
| 94 | method: function |
| 95 | class_to_bind: type or None |
| 96 | |
| 97 | Raises: |
| 98 | ValueError: method could not be inspected, so checks aren't |
| 99 | possible. Some methods and functions like built-ins |
| 100 | can't be inspected. |
| 101 | """ |
| 102 | import inspect |
| 103 | try: |
| 104 | self._args, varargs, varkw, defaults, _, _, _ = inspect.getfullargspec( |
| 105 | method) |
| 106 | except TypeError: |
| 107 | raise ValueError('Could not get argument specification for %r' % (method,)) |
| 108 | if (inspect.ismethod(method) or class_to_bind or |
| 109 | (hasattr(self, '_args') and len(self._args) > 0 and |
| 110 | self._args[0] == 'self')): |
| 111 | self._args = self._args[1:] # Skip 'self'. |
| 112 | self._method = method |
| 113 | self._instance = None # May contain the instance this is bound to. |
| 114 | self._instance = getattr(method, "__self__", None) |
| 115 | |
| 116 | # _bounded_to determines whether the method is bound or not |
| 117 | if self._instance: |
| 118 | self._bounded_to = self._instance.__class__ |
| 119 | else: |
| 120 | self._bounded_to = class_to_bind or getattr(method, "im_class", None) |
| 121 | |
| 122 | self._has_varargs = varargs is not None |
| 123 | self._has_varkw = varkw is not None |
| 124 | if defaults is None: |
| 125 | self._required_args = self._args |
| 126 | self._default_args = [] |
| 127 | else: |
| 128 | self._required_args = self._args[:-len(defaults)] |
| 129 | self._default_args = self._args[-len(defaults):] |