@@ -1,4 +1,9 @@
-__author__ = "jadmanski@google.com (John Admanski)"
+"""
+Utility library used for autotest library namespace configuration.
+
+@copyright Google 2007-2009
+@author John Admanski <jadmanski@google.com>
+"""
import os, sys
@@ -12,134 +17,195 @@ check_version.check_python_version()
import new, glob, traceback
+class namespace_config(object):
+ """
+ Class to perform namespace configuration for autotest.
-def _create_module(name):
- """Create a single top-level module"""
- module = new.module(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 = new.module(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)
+ This is what makes possible to use statements like
+ from autotest_lib.client.bin import package
+ """
+ def __init__(self, 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.
+
+ @param base_path: Path used to compute all relative paths needed for
+ the setup.
+ @param root_module_name: Top level name of the 'virtual' library
+ namespace.
+ """
+ # 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, '..'))
+ self.root_module_name = root_module_name
+ self.base_path = base_path
+
+
+ def _create_module(self, name):
+ """
+ Create a single top-level module.
+
+ @param name: Name of the module you wish to create.
+ """
+ module = new.module(name)
+ sys.modules[name] = module
+ return module
+
+
+ def _create_module_and_parents(self, name):
+ """
+ Create a module, and all the necessary parents.
+
+ @param name: Name of the module you wish to create.
+ """
+ parts = name.split(".")
+ # first create the top-level module
+ parent = self._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 = new.module(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(self, parent_module_name, path):
+ """
+ Import all the packages on a path into a parent module.
+
+ @param parent_module_name: Name of the parent module you want to use
+ @param path: Path that contains a number of python packages (libs)
+ """
+ # 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 _autotest_logging_handle_error(self, record):
+ """
+ Method to monkey patch into logging.Handler to replace handleError.
+
+ @param record: Logging record that is going to be treated.
+ """
+ # 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('Future logging formatting exceptions disabled.\n')
+
+ if self.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(self.base_path, "site-packages"))
+
+
+ def _monkeypatch_logging_handle_error(self):
+ """
+ Hack out logging.py to introduce a custom logging error handling
+ function.
+ """
+ # 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 = self._autotest_logging_handle_error
+
+
+ def setup(self):
+ """
+ Effectively creates the autotest_lib namespace.
+ """
+ # Some internal functions might need to reference those variables.
+ # It doesn't occur to me how to refactor the API in this file in a clean
+ # way to avoid
+ self._create_module_and_parents(self.root_module_name)
+ self._import_children_into_module(self.root_module_name, self.base_path)
+
+ if self.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(self.base_path, "site-packages"))
+
+ self._monkeypatch_logging_handle_error()
def import_module(module, from_where):
- """Equivalent to 'from from_where import module'
- Returns the corresponding module"""
+ """
+ Equivalent to 'from from_where import module'
+
+ @param module: Module intended to be loaded
+ @param from_where: Top level module where we want to import the module
+ @return: loaded 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('Future logging formatting exceptions disabled.\n')
-
- 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"))
-
-
-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.
+ Configures the autotest_lib namespace for use on a given autotest
+ entry point
- 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.
+ @param base_path: Path used to compute all relative paths needed for the
+ setup.
+ @param root_module_name: Top level name of the 'virtual' library namespace.
"""
- # 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()
+ configurator = namespace_config(base_path, root_module_name)
+ configurator.setup()