def _create_api_server(self, request_data, storage_path, options, configuration): # sandbox._create_dispatcher returns a singleton dispatcher instance made in sandbox self._dispatcher = sandbox._create_dispatcher( configuration, options) # the dispatcher may have passed environment variables, it should be propagated env_vars = self._dispatcher._configuration.modules[ 0]._app_info_external.env_variables or EnvironmentVariables( ) for module in configuration.modules: module_name = module._module_name if module_name == 'default' or module_name is None: module_settings = 'DJANGO_SETTINGS_MODULE' else: module_settings = '%s_DJANGO_SETTINGS_MODULE' % module_name if module_settings in env_vars: module_env_vars = module.env_variables or EnvironmentVariables( ) module_env_vars['DJANGO_SETTINGS_MODULE'] = env_vars[ module_settings] old_env_vars = module._app_info_external.env_variables new_env_vars = EnvironmentVariables.Merge( module_env_vars, old_env_vars) module._app_info_external.env_variables = new_env_vars self._dispatcher._configuration = configuration self._dispatcher._port = options.port self._dispatcher._host = options.host # Because the dispatcher is a singleton, we need to set the threadsafe override here # depending on what was passed to the runserver command. This entire file really needs rebuilding # we have way too many hacks in here! self._dispatcher._module_to_threadsafe_override[ configuration.modules[0]. module_name] = options.threadsafe_override self._dispatcher.request_data = request_data request_data._dispatcher = self._dispatcher sandbox._API_SERVER._host = options.api_host sandbox._API_SERVER.bind_addr = (options.api_host, options.api_port) from google.appengine.api import apiproxy_stub_map task_queue = apiproxy_stub_map.apiproxy.GetStub('taskqueue') # Make sure task running is enabled (it's disabled in the sandbox by default) if not task_queue._auto_task_running: task_queue._auto_task_running = True task_queue.StartBackgroundExecution() return sandbox._API_SERVER
def activate(sandbox_name, add_sdk_to_path=False, new_env_vars=None, **overrides): """Context manager for command-line scripts started outside of dev_appserver. :param sandbox_name: str, one of 'local', 'remote' or 'test' :param add_sdk_to_path: bool, optionally adds the App Engine SDK to sys.path :param options_override: an options structure to pass down to dev_appserver setup Available sandboxes: local: Adds libraries specified in app.yaml to the path and initializes local service stubs as though dev_appserver were running. remote: Adds libraries specified in app.yaml to the path and initializes remote service stubs. test: Adds libraries specified in app.yaml to the path and sets up no service stubs. Use this with `google.appengine.ext.testbed` to provide isolation for tests. Example usage: import djangae.sandbox as sandbox with sandbox.activate('local'): from django.core.management import execute_from_command_line execute_from_command_line(sys.argv) """ if sandbox_name not in SANDBOXES: raise RuntimeError('Unknown sandbox "{}"'.format(sandbox_name)) project_root = environment.get_application_root() # Store our original sys.path before we do anything, this must be tacked # onto the end of the other paths so we can access globally installed things (e.g. ipdb etc.) original_path = sys.path[:] # Setup paths as though we were running dev_appserver. This is similar to # what the App Engine script wrappers do. if add_sdk_to_path: try: import wrapper_util # Already on sys.path except ImportError: sys.path[0:0] = [_find_sdk_from_path()] import wrapper_util else: try: import wrapper_util except ImportError: raise RuntimeError("Couldn't find a recent enough Google App Engine SDK, make sure you are using at least 1.9.6") sdk_path = _find_sdk_from_python_path() _PATHS = wrapper_util.Paths(sdk_path) project_paths = [] # Paths under the application root system_paths = [] # All other paths app_root = environment.get_application_root() # We need to look at the original path, and make sure that any paths # which are under the project root are first, then any other paths # are added after the SDK ones for path in _PATHS.scrub_path(_SCRIPT_NAME, original_path): if commonprefix([app_root, path]) == app_root: project_paths.append(path) else: system_paths.append(path) # We build a list of SDK paths, and add any additional ones required for # the oauth client appengine_paths = _PATHS.script_paths(_SCRIPT_NAME) for path in _PATHS.oauth_client_extra_paths: if path not in appengine_paths: appengine_paths.append(path) # Now, we make sure that paths within the project take precedence, followed # by the SDK, then finally any paths from the system Python (for stuff like # ipdb etc.) sys.path = ( project_paths + appengine_paths + system_paths ) # Gotta set the runtime properly otherwise it changes appengine imports, like wepapp # when you are not running dev_appserver import yaml with open(os.path.join(project_root, 'app.yaml'), 'r') as app_yaml: app_yaml = yaml.load(app_yaml) os.environ['APPENGINE_RUNTIME'] = app_yaml.get('runtime', '') # Initialize as though `dev_appserver.py` is about to run our app, using all the # configuration provided in app.yaml. import google.appengine.tools.devappserver2.application_configuration as application_configuration import google.appengine.tools.devappserver2.python.sandbox as sandbox import google.appengine.tools.devappserver2.devappserver2 as devappserver2 import google.appengine.tools.devappserver2.wsgi_request_info as wsgi_request_info import google.appengine.ext.remote_api.remote_api_stub as remote_api_stub import google.appengine.api.apiproxy_stub_map as apiproxy_stub_map gae_args = [ s for s in sys.argv if any(s.lstrip('--').startswith(gae_option) for gae_option in WHITELISTED_DEV_APPSERVER_OPTIONS) ] # The argparser is the easiest way to get the default options. options = devappserver2.PARSER.parse_args([project_root] + gae_args) options.enable_task_running = False # Disable task running by default, it won't work without a running server options.skip_sdk_update_check = True for option in overrides: if not hasattr(options, option): raise ValueError("Unrecognized sandbox option: {}".format(option)) setattr(options, option, overrides[option]) configuration = application_configuration.ApplicationConfiguration(options.config_paths, app_id=options.app_id) # Enable built-in libraries from app.yaml without enabling the full sandbox. module = configuration.modules[0] for l in sandbox._enable_libraries(module.normalized_libraries): sys.path.insert(1, l) # Propagate provided environment variables to the sandbox. # This is required for the runserver management command settings flag, # which sets an environment variable needed by Django. from google.appengine.api.appinfo import EnvironmentVariables old_env_vars = module.env_variables if module.env_variables else {} if new_env_vars is None: new_env_vars = {} module._app_info_external.env_variables = EnvironmentVariables.Merge( old_env_vars, new_env_vars, ) try: global _OPTIONS global _CONFIG _CONFIG = configuration _OPTIONS = options # Store the options globally so they can be accessed later kwargs = dict( devappserver2=devappserver2, configuration=configuration, options=options, wsgi_request_info=wsgi_request_info, remote_api_stub=remote_api_stub, apiproxy_stub_map=apiproxy_stub_map, ) with SANDBOXES[sandbox_name](**kwargs): yield finally: sys.path = original_path
def _set_dispatcher(self, dispatcher): """ Ignore explicit setting of _dispatcher, use our own """ if dispatcher is None: # Allow wiping the patched dispatcher self._patched_dispatcher = None return if self._patched_dispatcher: # We already created the dispatcher, ignore further sets logging.warning("Attempted to set _dispatcher twice") return # When the dispatcher is created this property is set so we use it # to construct *our* dispatcher configuration = dispatcher._configuration # We store options in .start() so it's available here options = self.options # sandbox._create_dispatcher returns a singleton dispatcher instance made in sandbox self._patched_dispatcher = sandbox._create_dispatcher( configuration, options ) # the dispatcher may have passed environment variables, it should be propagated env_vars = self._dispatcher._configuration.modules[0]._app_info_external.env_variables or EnvironmentVariables() for module in configuration.modules: module_name = module._module_name if module_name == 'default' or module_name is None: module_settings = 'DJANGO_SETTINGS_MODULE' else: module_settings = '%s_DJANGO_SETTINGS_MODULE' % module_name if module_settings in env_vars: module_env_vars = module.env_variables or EnvironmentVariables() module_env_vars['DJANGO_SETTINGS_MODULE'] = env_vars[module_settings] old_env_vars = module._app_info_external.env_variables new_env_vars = EnvironmentVariables.Merge(module_env_vars, old_env_vars) module._app_info_external.env_variables = new_env_vars self._dispatcher._configuration = configuration self._dispatcher._port = options.port self._dispatcher._host = options.host # Because the dispatcher is a singleton, we need to set the threadsafe override here # depending on what was passed to the runserver command. This entire file really needs rebuilding # we have way too many hacks in here! self._dispatcher._module_to_threadsafe_override[ configuration.modules[0].module_name ] = options.threadsafe_override # self._dispatcher.request_data = request_data # request_data._dispatcher = self._dispatcher sandbox._API_SERVER._host = options.api_host sandbox._API_SERVER.bind_addr = (options.api_host, options.api_port) from google.appengine.api import apiproxy_stub_map task_queue = apiproxy_stub_map.apiproxy.GetStub('taskqueue') # Make sure task running is enabled (it's disabled in the sandbox by default) if not task_queue._auto_task_running: task_queue._auto_task_running = True task_queue.StartBackgroundExecution()