blob: 602c4f48fb8495b9d02709d276e805f03420dd81 [file] [log] [blame]
Allen Li464220f2017-09-12 17:14:22 -07001# Copyright 2017 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Kludges to support legacy Autotest code.
6
Allen Libca5d012017-10-20 13:44:36 -07007Autotest imports should be done by calling patch() first and then
8calling load(). patch() should only be called once from a script's main
9function.
Allen Li464220f2017-09-12 17:14:22 -070010"""
11
12from __future__ import absolute_import
13from __future__ import division
14from __future__ import print_function
15
16import imp
17import importlib
18import logging
19import os
20import site
21import sys
22
23import autotest_lib
24
25_AUTOTEST_DIR = autotest_lib.__path__[0]
26_SITEPKG_DIR = os.path.join(_AUTOTEST_DIR, 'site-packages')
27
28_setup_done = False
29
30logger = logging.getLogger(__name__)
31
32
Allen Libca5d012017-10-20 13:44:36 -070033def patch():
34 """Monkeypatch everything needed to get Autotest working.
35
36 This should be called before any calls to load(). Only the main
37 function in scripts should call this function.
38
39 Unlike monkeypatch() which is more low-level, this patches not just
40 imports, but also other things in Autotest what would generally be
41 needed to use it.
42 """
43 monkeypatch()
44
45 # Needed to set up Django environment variables.
46 load('frontend.setup_django_environment')
47
48 # Monkey patch package paths that Django uses to be absolute.
49 settings = load('frontend.settings')
50 settings.INSTALLED_APPS = (
51 'autotest_lib.frontend.afe',
52 'autotest_lib.frontend.tko',
53 'django.contrib.admin',
54 'django.contrib.auth',
55 'django.contrib.contenttypes',
56 'django.contrib.sessions',
57 'django.contrib.sites',
58 )
59
60
Allen Li464220f2017-09-12 17:14:22 -070061def monkeypatch():
Allen Libca5d012017-10-20 13:44:36 -070062 """Monkeypatch Autotest imports.
Allen Li464220f2017-09-12 17:14:22 -070063
Allen Li2678d362017-10-11 16:59:07 -070064 This should be called before any calls to load(). Only the main
65 function in scripts should call this function.
Allen Li464220f2017-09-12 17:14:22 -070066
67 This should be called no more than once.
68
Allen Li2678d362017-10-11 16:59:07 -070069 This adds Autotest's site-packages to the import path and modifies
70 sys.meta_path so that all common.py imports are no-ops.
Allen Li464220f2017-09-12 17:14:22 -070071 """
72 global _setup_done
73 assert not _setup_done
74 site.addsitedir(_SITEPKG_DIR)
75 sys.meta_path.insert(0, _CommonRemovingFinder())
76 _setup_done = True
77
78
79class _CommonRemovingFinder(object):
80 """Python import finder that neuters Autotest's common.py
81
82 The common module is replaced with an empty module everywhere it is
83 imported. common.py should have only been imported for side
84 effects, so nothing should actually use the imported module.
85
86 See also https://www.python.org/dev/peps/pep-0302/
87 """
88
89 def find_module(self, fullname, path=None):
90 """Find module."""
91 del path # unused
92 if not self._is_autotest_common(fullname):
93 return None
94 logger.debug('Dummying out %s import', fullname)
95 return self
96
97 def _is_autotest_common(self, fullname):
98 return (fullname.partition('.')[0] == 'autotest_lib'
99 and fullname.rpartition('.')[-1] == 'common')
100
101 def load_module(self, fullname):
102 """Load module."""
Allen Libca5d012017-10-20 13:44:36 -0700103 if fullname in sys.modules: # pragma: no cover
Allen Li464220f2017-09-12 17:14:22 -0700104 return sys.modules[fullname]
105 mod = imp.new_module(fullname)
106 mod.__file__ = '<removed>'
107 mod.__loader__ = self
108 mod.__package__ = fullname.rpartition('.')[0]
109 sys.modules[fullname] = mod
110 return mod
111
112
113def load(name):
114 """Import module from autotest.
115
Allen Li2678d362017-10-11 16:59:07 -0700116 This enforces that monkeypatch() is called first.
Allen Licc153502017-09-15 16:08:25 -0700117
118 @param name: name of module as string, e.g., 'frontend.afe.models'
Allen Li464220f2017-09-12 17:14:22 -0700119 """
120 if not _setup_done:
121 raise ImportError('cannot load Autotest modules before monkeypatching')
122 relpath = name.lstrip('.')
123 return importlib.import_module('.%s' % relpath, package='autotest_lib')