| import os |
| import re |
| import sys |
| |
| # This must run on Python versions less than 2.4. |
| dirname = os.path.dirname(sys.modules[__name__].__file__) |
| common_dir = os.path.abspath(os.path.join(dirname, 'common_lib')) |
| sys.path.insert(0, common_dir) |
| import check_version |
| sys.path.pop(0) |
| |
| |
| def _get_pyversion_from_args(): |
| """Extract, format, & pop the current py_version from args, if provided.""" |
| py_version = 2 |
| py_version_re = re.compile(r'--py_version=(\w+)\b') |
| |
| version_found = False |
| for i, arg in enumerate(sys.argv): |
| if not arg.startswith('--py_version'): |
| continue |
| result = py_version_re.search(arg) |
| if result: |
| if version_found: |
| raise ValueError('--py_version may only be specified once.') |
| py_version = result.group(1) |
| version_found = True |
| if py_version not in ('2', '3'): |
| raise ValueError('Python version must be "2" or "3".') |
| |
| # Remove the arg so other argparsers don't get grumpy. |
| sys.argv.pop(i) |
| |
| return py_version |
| |
| |
| def _desired_version(): |
| """ |
| Returns desired python version. |
| |
| If the PY_VERSION env var is set, just return that. This is the case |
| when autoserv kicks of autotest on the server side via a job.run(), or |
| a process created a subprocess. |
| |
| Otherwise, parse & pop the sys.argv for the '--py_version' flag. If no |
| flag is set, default to python 2 (for now). |
| |
| """ |
| # Even if the arg is in the env vars, we will attempt to get it from the |
| # args, so that it can be popped prior to other argparsers hitting. |
| py_version = _get_pyversion_from_args() |
| |
| if os.getenv('PY_VERSION'): |
| return int(os.getenv('PY_VERSION')) |
| |
| os.environ['PY_VERSION'] = str(py_version) |
| return int(py_version) |
| |
| |
| desired_version = _desired_version() |
| if desired_version == sys.version_info.major: |
| os.environ['AUTOTEST_NO_RESTART'] = 'True' |
| else: |
| # There are cases were this can be set (ie by test_that), but a subprocess |
| # is launched in the incorrect version. |
| if os.getenv('AUTOTEST_NO_RESTART'): |
| del os.environ['AUTOTEST_NO_RESTART'] |
| check_version.check_python_version(desired_version) |
| |
| import glob, traceback, types |
| |
| |
| def _create_module(name): |
| """Create a single top-level module""" |
| module = types.ModuleType(name) |
| sys.modules[name] = module |
| return module |
| |
| |
| def _create_module_and_parents(name): |
| """Create a module, and all the necessary parents""" |
| parts = name.split('.') |
| # first create the top-level module |
| parent = _create_module(parts[0]) |
| created_parts = [parts[0]] |
| parts.pop(0) |
| # now, create any remaining child modules |
| while parts: |
| child_name = parts.pop(0) |
| module = types.ModuleType(child_name) |
| setattr(parent, child_name, module) |
| created_parts.append(child_name) |
| sys.modules['.'.join(created_parts)] = module |
| parent = module |
| |
| |
| def _import_children_into_module(parent_module_name, path): |
| """Import all the packages on a path into a parent module""" |
| # find all the packages at 'path' |
| names = [] |
| for filename in os.listdir(path): |
| full_name = os.path.join(path, filename) |
| if not os.path.isdir(full_name): |
| continue # skip files |
| if '.' in filename: |
| continue # if '.' is in the name it's not a valid package name |
| if not os.access(full_name, os.R_OK | os.X_OK): |
| continue # need read + exec access to make a dir importable |
| if '__init__.py' in os.listdir(full_name): |
| names.append(filename) |
| # import all the packages and insert them into 'parent_module' |
| sys.path.insert(0, path) |
| for name in names: |
| module = __import__(name) |
| # add the package to the parent |
| parent_module = sys.modules[parent_module_name] |
| setattr(parent_module, name, module) |
| full_name = parent_module_name + '.' + name |
| sys.modules[full_name] = module |
| # restore the system path |
| sys.path.pop(0) |
| |
| |
| def import_module(module, from_where): |
| """Equivalent to 'from from_where import module' |
| Returns the corresponding module""" |
| from_module = __import__(from_where, globals(), locals(), [module]) |
| return getattr(from_module, module) |
| |
| |
| def _autotest_logging_handle_error(self, record): |
| """Method to monkey patch into logging.Handler to replace handleError.""" |
| # The same as the default logging.Handler.handleError but also prints |
| # out the original record causing the error so there is -some- idea |
| # about which call caused the logging error. |
| import logging |
| if logging.raiseExceptions: |
| # Avoid recursion as the below output can end up back in here when |
| # something has *seriously* gone wrong in autotest. |
| logging.raiseExceptions = 0 |
| sys.stderr.write('Exception occurred formatting message: ' |
| '%r using args %r\n' % (record.msg, record.args)) |
| traceback.print_stack() |
| sys.stderr.write('-' * 50 + '\n') |
| traceback.print_exc() |
| sys.stderr.write('Future logging formatting exceptions disabled.\n') |
| |
| |
| def _monkeypatch_logging_handle_error(): |
| # Hack out logging.py* |
| logging_py = os.path.join(os.path.dirname(__file__), 'common_lib', |
| 'logging.py*') |
| if glob.glob(logging_py): |
| os.system('rm -f %s' % logging_py) |
| |
| # Monkey patch our own handleError into the logging module's StreamHandler. |
| # A nicer way of doing this -might- be to have our own logging module define |
| # an autotest Logger instance that added our own Handler subclass with this |
| # handleError method in it. But that would mean modifying tons of code. |
| import logging |
| assert callable(logging.Handler.handleError) |
| logging.Handler.handleError = _autotest_logging_handle_error |
| |
| |
| def setup(base_path, root_module_name=""): |
| """ |
| Perform all the necessary setup so that all the packages at |
| 'base_path' can be imported via "import root_module_name.package". |
| If root_module_name is empty, then all the packages at base_path |
| are inserted as top-level packages. |
| |
| Also, setup all the common.* aliases for modules in the common |
| library. |
| |
| The setup must be different if you are running on an Autotest server |
| or on a test machine that just has the client directories installed. |
| """ |
| # Hack... Any better ideas? |
| if (root_module_name == 'autotest_lib.client' and |
| os.path.exists(os.path.join(os.path.dirname(__file__), |
| '..', 'server'))): |
| root_module_name = 'autotest_lib' |
| base_path = os.path.abspath(os.path.join(base_path, '..')) |
| |
| _create_module_and_parents(root_module_name) |
| _import_children_into_module(root_module_name, base_path) |
| |
| if root_module_name == 'autotest_lib': |
| # Allow locally installed third party packages to be found |
| # before any that are installed on the system itself when not. |
| # running as a client. |
| # This is primarily for the benefit of frontend and tko so that they |
| # may use libraries other than those available as system packages. |
| sys.path.insert(0, os.path.join(base_path, 'site-packages')) |
| |
| _monkeypatch_logging_handle_error() |