Beispiel #1
0
def init_testbed():
    try:
        import PIL
        IGNORED_STUBS = []
    except ImportError:
        logger.warning("Unable to initialize the images stub as Pillow is unavailable")
        IGNORED_STUBS = [
            "init_images_stub"
        ]

    # We allow users to disable scattered IDs in tests. This primarily for running Django tests that
    # assume implicit ordering (yeah, annoying)
    use_scattered = not getattr(settings, "DJANGAE_SEQUENTIAL_IDS_IN_TESTS", False)

    stub_kwargs = {
        "init_taskqueue_stub": {
            "root_path": environment.get_application_root()
        },
        "init_datastore_v3_stub": {
            "use_sqlite": True,
            "auto_id_policy": testbed.AUTO_ID_POLICY_SCATTERED if use_scattered else testbed.AUTO_ID_POLICY_SEQUENTIAL,
            "consistency_policy": datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)
        }
    }

    get_context().reset(); # Reset any context caching
    bed = testbed.Testbed()
    bed.activate()
    for init_name in testbed.INIT_STUB_METHOD_NAMES.values():
        if init_name in IGNORED_STUBS:
            continue

        getattr(bed, init_name)(**stub_kwargs.get(init_name, {}))

    return bed
Beispiel #2
0
def init_testbed():
    IGNORED_STUBS = []

    # We allow users to disable scattered IDs in tests. This primarily for running Django tests that
    # assume implicit ordering (yeah, annoying)
    use_scattered = not getattr(settings, "DJANGAE_SEQUENTIAL_IDS_IN_TESTS",
                                False)

    stub_kwargs = {
        "init_taskqueue_stub": {
            "root_path": environment.get_application_root()
        },
        "init_datastore_v3_stub": {
            "use_sqlite":
            True,
            "auto_id_policy":
            testbed.AUTO_ID_POLICY_SCATTERED
            if use_scattered else testbed.AUTO_ID_POLICY_SEQUENTIAL,
            "consistency_policy":
            datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)
        }
    }

    get_context().reset()
    # Reset any context caching
    bed = testbed.Testbed()
    bed.activate()
    for init_name in testbed.INIT_STUB_METHOD_NAMES.values():
        if init_name in IGNORED_STUBS:
            continue

        getattr(bed, init_name)(**stub_kwargs.get(init_name, {}))

    return bed
Beispiel #3
0
def start_emulators(persist_data, emulators=None, storage_dir=None, task_target_port=None, autodetect_task_port=True):
    # This prevents restarting of the emulators when Django code reload
    # kicks in
    if os.environ.get(DJANGO_AUTORELOAD_ENV) == 'true':
        return

    emulators = emulators or _ALL_EMULATORS
    storage_dir = storage_dir or os.path.join(get_application_root(), ".storage")

    if "datastore" in emulators:
        os.environ["DATASTORE_EMULATOR_HOST"] = "127.0.0.1:%s" % DATASTORE_PORT
        os.environ["DATASTORE_PROJECT_ID"] = "example"

        # Start the cloud datastore emulator
        command = "gcloud beta emulators datastore start --consistency=1.0 --quiet --project=example"
        command += " --host-port=127.0.0.1:%s" % DATASTORE_PORT

        if not persist_data:
            command += " --no-store-on-disk"

        _ACTIVE_EMULATORS["datastore"] = _launch_process(command)
        _wait_for_datastore(DATASTORE_PORT)

    if "tasks" in emulators:
        from djangae.tasks import cloud_tasks_parent_path
        default_queue = "%s/queues/default" % cloud_tasks_parent_path()

        if task_target_port is None:
            if sys.argv[1] == "runserver" and autodetect_task_port:
                from django.core.management.commands.runserver import Command as RunserverCommand
                parser = RunserverCommand().create_parser('django', 'runserver')
                args = parser.parse_args(sys.argv[2:])
                if args.addrport:
                    task_target_port = args.addrport.split(":")[-1]
                else:
                    task_target_port = _DJANGO_DEFAULT_PORT
            else:
                task_target_port = _DJANGO_DEFAULT_PORT

        os.environ["TASKS_EMULATOR_HOST"] = "127.0.0.1:%s" % TASKS_PORT
        _ACTIVE_EMULATORS["tasks"] = _launch_process(
            "gcloud-tasks-emulator start -q --port=%s --target-port=%s --default-queue=%s" % (
                TASKS_PORT, task_target_port, default_queue
            )
        )
        _wait_for_tasks(TASKS_PORT)

    if "storage" in emulators:
        os.environ["STORAGE_EMULATOR_HOST"] = "http://127.0.0.1:%s" % STORAGE_PORT
        command = "gcloud-storage-emulator start -q --port=%s" % STORAGE_PORT

        if not persist_data:
            command += " --no-store-on-disk"

        _ACTIVE_EMULATORS["storage"] = _launch_process(command)
        _wait_for_storage(STORAGE_PORT)
def init_testbed():
    # We don't initialize the datastore stub here, that needs to be done by Django's create_test_db and destroy_test_db.
    IGNORED_STUBS = [ "init_datastore_v3_stub" ]

    stub_kwargs = {
        "init_taskqueue_stub": {
            "root_path": environment.get_application_root()
        }
    }
    bed = testbed.Testbed()
    bed.activate()
    for init_name in testbed.INIT_STUB_METHOD_NAMES.values():
        if init_name in IGNORED_STUBS:
            continue

        getattr(bed, init_name)(**stub_kwargs.get(init_name, {}))

    return bed
Beispiel #5
0
def init_testbed():
    # We don't initialize the datastore stub here, that needs to be done by Django's create_test_db and destroy_test_db.
    IGNORED_STUBS = ["init_datastore_v3_stub"]

    stub_kwargs = {
        "init_taskqueue_stub": {
            "root_path": environment.get_application_root()
        }
    }
    bed = testbed.Testbed()
    bed.activate()
    for init_name in testbed.INIT_STUB_METHOD_NAMES.values():
        if init_name in IGNORED_STUBS:
            continue

        getattr(bed, init_name)(**stub_kwargs.get(init_name, {}))

    return bed
Beispiel #6
0
    def _match_handler(self, url):
        """
        Load script handler configurations from app.yaml and try to match
        the provided url path to a url_maps regex.
        """
        app_yaml_path = os.path.join(get_application_root(), "app.yaml")
        config = ModuleConfiguration(app_yaml_path)

        url_maps = config.handlers
        script_handlers = [
            _ScriptHandler(maps) for maps in url_maps
            if maps.GetHandlerType() == appinfo.HANDLER_SCRIPT
        ]

        for handler in script_handlers:
            if handler.match(url):
                return handler

        raise AssertionError('No handler found for {url}'.format(url=url))
Beispiel #7
0
    def _match_handler(self, url):
        """
        Load script handler configurations from app.yaml and try to match
        the provided url path to a url_maps regex.
        """
        app_yaml_path = os.path.join(get_application_root(), "app.yaml")
        config = ModuleConfiguration(app_yaml_path)

        url_maps = config.handlers
        script_handlers = [
            _ScriptHandler(maps) for
            maps in url_maps if
            maps.GetHandlerType() == appinfo.HANDLER_SCRIPT
        ]

        for handler in script_handlers:
            if handler.match(url):
                return handler

        raise AssertionError('No handler found for {url}'.format(url=url))
Beispiel #8
0
    def test_deferred_builtin_on(self):
        # Read and parse app.yaml
        app_yaml_path = os.path.join(get_application_root(), "app.yaml")
        with open(app_yaml_path, 'r') as f:
            app_yaml = yaml.load(f.read())
        builtins = app_yaml.get('builtins', [])

        # Switch on deferred builtin
        builtins.append({'deferred': 'on'})
        app_yaml['builtins'] = builtins

        # Write to temporary app.yaml
        temp_app_yaml_dir = tempfile.mkdtemp()
        temp_app_yaml_path = os.path.join(temp_app_yaml_dir, "app.yaml")
        temp_app_yaml = file(temp_app_yaml_path, 'w')
        yaml.dump(app_yaml, temp_app_yaml)

        with sleuth.switch('djangae.checks.get_application_root', lambda : temp_app_yaml_dir) as mock_app_root:
            warnings = check_deferred_builtin()
            self.assertEqual(len(warnings), 1)
            self.assertEqual(warnings[0].id, 'djangae.W001')
Beispiel #9
0
def check_deferred_builtin(app_configs=None, **kwargs):
    """
    Check that the deferred builtin is switched off, as it'll override Djangae's deferred handler
    """
    from google.appengine.tools.devappserver2.application_configuration import ModuleConfiguration

    app_yaml_path = os.path.join(get_application_root(), "app.yaml")
    config = ModuleConfiguration(app_yaml_path)
    errors = []

    for handler in config.handlers:
        if handler.url == '/_ah/queue/deferred':
            if handler.script == 'google.appengine.ext.deferred.application':
                errors.append(
                    Warning(
                        "Deferred builtin is switched on. This overrides Djangae's deferred handler",
                        hint='Remove deferred builtin from app.yaml',
                        id='djangae.W001'))
            break

    return errors
Beispiel #10
0
    def test_deferred_builtin_on(self):
        # Read and parse app.yaml
        app_yaml_path = os.path.join(get_application_root(), "app.yaml")
        with open(app_yaml_path, 'r') as f:
            app_yaml = yaml.load(f.read())
        builtins = app_yaml.get('builtins', [])

        # Switch on deferred builtin
        builtins.append({'deferred': 'on'})
        app_yaml['builtins'] = builtins

        # Write to temporary app.yaml
        temp_app_yaml_dir = tempfile.mkdtemp()
        temp_app_yaml_path = os.path.join(temp_app_yaml_dir, "app.yaml")
        temp_app_yaml = file(temp_app_yaml_path, 'w')
        yaml.dump(app_yaml, temp_app_yaml)

        with sleuth.switch('djangae.checks.get_application_root', lambda : temp_app_yaml_dir) as mock_app_root:
            warnings = checks.check_deferred_builtin()
            self.assertEqual(len(warnings), 1)
            self.assertEqual(warnings[0].id, 'djangae.W001')
Beispiel #11
0
def check_deferred_builtin(app_configs=None, **kwargs):
    """
    Check that the deferred builtin is switched off, as it'll override Djangae's deferred handler
    """
    from google.appengine.tools.devappserver2.application_configuration import ModuleConfiguration

    app_yaml_path = os.path.join(get_application_root(), "app.yaml")
    config = ModuleConfiguration(app_yaml_path)
    errors = []

    for handler in config.handlers:
        if handler.url == '/_ah/queue/deferred':
            if handler.script == 'google.appengine.ext.deferred.application':
                errors.append(
                    Warning(
                        "Deferred builtin is switched on. This overrides Djangae's deferred handler",
                        hint='Remove deferred builtin from app.yaml',
                        id='djangae.W001'
                    )
                )
            break

    return errors
Beispiel #12
0
import os
import re
import sys
import argparse

import djangae.sandbox as sandbox
from djangae import environment

DEFAULTS = {
    "storage_path": os.path.join(environment.get_application_root(), ".storage"),
    "port": 8000,
    "admin_port": 8001,
    "api_port": 8002,
    "automatic_restart": "True",
    "allow_skipped_files": "True",
    "app_id": "managepy",
}


def execute_from_command_line(argv=None, **sandbox_overrides):
    """Wraps Django's `execute_from_command_line` to initialize a djangae
    sandbox before running a management command.
    """
    argv = argv or sys.argv[:]

    djangae_parser = argparse.ArgumentParser(description='Djangae arguments', add_help=False)
    djangae_parser.add_argument('--sandbox', default=sandbox.LOCAL, choices=sandbox.SANDBOXES.keys())
    djangae_parser.add_argument('--app_id', default=None, help='GAE APPLICATION ID')

    ignored_args = ('-v', '--version')
    stashed_args = [arg for arg in argv[1:] if arg in ignored_args]
Beispiel #13
0
def _get_project_index_file():
    project_index_file = os.path.join(environment.get_application_root(),
                                      "djangaeidx.yaml")
    return project_index_file
Beispiel #14
0
def start_emulators(
    persist_data: bool,
    project_id: str = DEFAULT_PROJECT_ID,
    emulators: Sequence[str] = _ALL_EMULATORS,
    datastore_port: int = DATASTORE_PORT,
    datastore_dir: Optional[str] = None,
    tasks_port: int = TASKS_PORT,
    task_target_port: Optional[int] = None,
    autodetect_task_port: bool = True,
    storage_port: int = STORAGE_PORT,
    storage_dir: Optional[str] = None,

):
    # This prevents restarting of the emulators when Django code reload kicks in
    if os.environ.get(DJANGO_AUTORELOAD_ENV) == 'true':
        return

    storage_dir = storage_dir or os.path.join(get_application_root(), ".storage")
    enable_test_environment_variables()

    if "datastore" in emulators:
        os.environ["DATASTORE_EMULATOR_HOST"] = "127.0.0.1:%s" % datastore_port
        os.environ["DATASTORE_PROJECT_ID"] = project_id

        # Start the cloud datastore emulator
        command = "gcloud beta emulators datastore start --consistency=1.0 --quiet --project=example"
        command += " --host-port=127.0.0.1:%s" % datastore_port

        if datastore_dir:
            command += " --data-dir=%s" % datastore_dir
        if not persist_data:
            command += " --no-store-on-disk"

        _ACTIVE_EMULATORS["datastore"] = _launch_process(command)
        _wait_for_datastore(datastore_port)

    if "tasks" in emulators:
        from djangae.tasks import cloud_tasks_parent_path, cloud_tasks_project, cloud_tasks_location
        default_queue = "%s/queues/default" % cloud_tasks_parent_path()

        if task_target_port is None:
            if sys.argv[1] == "runserver" and autodetect_task_port:
                from django.core.management.commands.runserver import Command as RunserverCommand
                parser = RunserverCommand().create_parser('django', 'runserver')
                args = parser.parse_args(sys.argv[2:])
                if args.addrport:
                    task_target_port = args.addrport.split(":")[-1]
                else:
                    task_target_port = _DJANGO_DEFAULT_PORT
            else:
                task_target_port = _DJANGO_DEFAULT_PORT

        command = "gcloud-tasks-emulator start -q --port=%s --target-port=%s --default-queue=%s" % (
            tasks_port, task_target_port, default_queue
        )

        # If the project contains a queue.yaml, pass it to the Tasks Emulator so that those queues
        # can be created (needs version >= 0.4.0)
        queue_yaml = os.path.join(get_application_root(), "queue.yaml")
        if os.path.exists(queue_yaml):
            command += " --queue-yaml=%s --queue-yaml-project=%s --queue-yaml-location=%s" % (
                queue_yaml, cloud_tasks_project(), cloud_tasks_location()
            )

        os.environ["TASKS_EMULATOR_HOST"] = "127.0.0.1:%s" % tasks_port
        _ACTIVE_EMULATORS["tasks"] = _launch_process(command)
        _wait_for_tasks(tasks_port)

    if "storage" in emulators:
        os.environ["STORAGE_EMULATOR_HOST"] = "http://127.0.0.1:%s" % storage_port
        command = "gcloud-storage-emulator start -q --port=%s --default-bucket=%s" % (
            storage_port, DEFAULT_BUCKET)

        if not persist_data:
            command += " --no-store-on-disk"

        _ACTIVE_EMULATORS["storage"] = _launch_process(command)
        _wait_for_storage(storage_port)
Beispiel #15
0
    def inner_run(self, *args, **options):
        import sys

        shutdown_message = options.get('shutdown_message', '')

        quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'

        from djangae.environment import get_application_root
        from djangae.sandbox import _find_sdk_from_python_path
        from djangae.blobstore_service import stop_blobstore_service

        from django.conf import settings
        from django.utils import translation

        stop_blobstore_service()

        # Check for app.yaml
        expected_path = os.path.join(get_application_root(), "app.yaml")
        if not os.path.exists(expected_path):
            sys.stderr.write("Unable to find app.yaml at '%s'\n" % expected_path)
            sys.exit(1)

        self.stdout.write("Validating models...\n\n")
        self.check(display_num_errors=True)
        self.stdout.write((
            "%(started_at)s\n"
            "Djangae version %(djangae_version)s\n"
            "Django version %(django_version)s, using settings %(settings)r\n"
            "Starting development server at http://%(addr)s:%(port)s/\n"
            "Quit the server with %(quit_command)s.\n"
        ) % {
            "started_at": datetime.now().strftime('%B %d, %Y - %X'),
            "django_version": self.get_version(),
            "settings": settings.SETTINGS_MODULE,
            "addr": self._raw_ipv6 and '[%s]' % self.addr or self.addr,
            "port": self.port,
            "quit_command": quit_command,
            "djangae_version": DJANGAE_VERSION
        })
        sys.stdout.write("\n")
        sys.stdout.flush()

        # django.core.management.base forces the locale to en-us. We should
        # set it up correctly for the first request (particularly important
        # in the "--noreload" case).
        translation.activate(settings.LANGUAGE_CODE)

        # Will have been set by setup_paths
        sdk_path = _find_sdk_from_python_path()

        from google.appengine.tools.devappserver2 import devappserver2
        from google.appengine.tools.devappserver2 import python_runtime

        from djangae import sandbox

        # Add any additional modules specified in the settings
        additional_modules = getattr(settings, "DJANGAE_ADDITIONAL_MODULES", [])
        if additional_modules:
            sandbox._OPTIONS.config_paths.extend(additional_modules)

        if self.addr != sandbox._OPTIONS.host:
            sandbox._OPTIONS.host = sandbox._OPTIONS.admin_host = sandbox._OPTIONS.api_host = self.addr

        # Extra options for `dev_appserver.py`
        for param, value in self.gae_options.items():
            setattr(sandbox._OPTIONS, param, value)

        # External port is a new flag introduced in 1.9.19
        current_version = _VersionList(GetVersionObject()['release'])
        if current_version >= _VersionList('1.9.19') or \
                current_version == sandbox.TEMP_1_9_49_VERSION_NO:
            sandbox._OPTIONS.external_port = None

        # Apply equivalent options for Django args
        sandbox._OPTIONS.automatic_restart = self.use_reloader
        sandbox._OPTIONS.threadsafe_override = self.use_threading

        if sandbox._OPTIONS.host == "127.0.0.1" and os.environ["HTTP_HOST"].startswith("localhost"):
            hostname = "localhost"
            sandbox._OPTIONS.host = "localhost"
        else:
            hostname = sandbox._OPTIONS.host

        os.environ["HTTP_HOST"] = "%s:%s" % (hostname, sandbox._OPTIONS.port)
        os.environ['SERVER_NAME'] = os.environ['HTTP_HOST'].split(':', 1)[0]
        os.environ['SERVER_PORT'] = os.environ['HTTP_HOST'].split(':', 1)[1]
        os.environ['DEFAULT_VERSION_HOSTNAME'] = '%s:%s' % (os.environ['SERVER_NAME'], os.environ['SERVER_PORT'])

        from google.appengine.api.appinfo import EnvironmentVariables

        class NoConfigDevServer(devappserver2.DevelopmentServer):
            """
                This is horrible, but unfortunately necessary.

                Because we want to enable a sandbox outside of runserver (both when
                running different management commands, but also before/after dev_appserver)
                we have to make sure the following are true:

                1. There is only ever one api server
                2. There is only ever one dispatcher

                Unfortunately, most of the setup is done inside .start() of the DevelopmentServer
                class, there is not really an easy way to hook into part of this without overriding the
                whole .start() method which makes things even more brittle.

                What we do here is hook in at the point that self._dispatcher is set. We ignore whatever
                dispatcher is passed in, but user our own one. We patch api server creation in sandbox.py
                so only ever one api server exists.
            """
            def __init__(self, *args, **kwargs):
                self._patched_dispatcher = None
                super(NoConfigDevServer, self).__init__(*args, **kwargs)

            def start(self, options):
                self.options = options
                return super(NoConfigDevServer, self).start(options)

            def _get_dispatcher(self):
                return self._patched_dispatcher

            def _create_api_server(self, *args, **kwargs):
                """
                    For SDK around 1.9.40 - just return the existing API server
                """
                return sandbox._API_SERVER

            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()

            _dispatcher = property(fget=_get_dispatcher, fset=_set_dispatcher)

        from google.appengine.tools.devappserver2 import module

        def fix_watcher_files(regex):
            """ Monkeypatch dev_appserver's file watcher to ignore any unwanted dirs or files. """
            from google.appengine.tools.devappserver2 import watcher_common
            watcher_common._IGNORED_REGEX = regex
            watcher_common.ignore_file = ignore_file
            watcher_common.skip_ignored_dirs = skip_ignored_dirs

        regex = sandbox._CONFIG.modules[0].skip_files
        if regex:
            fix_watcher_files(regex)

        def logging_wrapper(func):
            """
                Changes logging to use the DJANGO_COLORS settings
            """
            def _wrapper(level, format, *args, **kwargs):
                if args and len(args) == 1 and isinstance(args[0], dict):
                    args = args[0]
                    status = str(args.get("status", 200))
                else:
                    status = "200"

                try:
                    msg = format % args
                except UnicodeDecodeError:
                    msg += "\n" # This is what Django does in WSGIRequestHandler.log_message

                # Utilize terminal colors, if available
                if status[0] == '2':
                    # Put 2XX first, since it should be the common case
                    msg = self.style.HTTP_SUCCESS(msg)
                elif status[0] == '1':
                    msg = self.style.HTTP_INFO(msg)
                elif status == '304':
                    msg = self.style.HTTP_NOT_MODIFIED(msg)
                elif status[0] == '3':
                    msg = self.style.HTTP_REDIRECT(msg)
                elif status == '404':
                    msg = self.style.HTTP_NOT_FOUND(msg)
                elif status[0] == '4':
                    # 0x16 = Handshake, 0x03 = SSL 3.0 or TLS 1.x
                    if status.startswith(str('\x16\x03')):
                        msg = ("You're accessing the development server over HTTPS, "
                            "but it only supports HTTP.\n")
                    msg = self.style.HTTP_BAD_REQUEST(msg)
                else:
                    # Any 5XX, or any other response
                    msg = self.style.HTTP_SERVER_ERROR(msg)

                return func(level, msg)
            return _wrapper

        module.logging.log = logging_wrapper(module.logging.log)

        python_runtime._RUNTIME_PATH = os.path.join(sdk_path, '_python_runtime.py')
        python_runtime._RUNTIME_ARGS = [sys.executable, python_runtime._RUNTIME_PATH]

        dev_server = NoConfigDevServer()

        try:
            dev_server.start(sandbox._OPTIONS)
            try:
                shutdown.wait_until_shutdown()
            except KeyboardInterrupt:
                pass
        finally:
            dev_server.stop()


        if shutdown_message:
            sys.stdout.write(shutdown_message)

        return
Beispiel #16
0
def _get_project_index_file():
    project_index_file = os.path.join(environment.get_application_root(), "djangaeidx.yaml")
    return project_index_file
Beispiel #17
0
def start_emulators(
    persist_data: bool,
    project_id: str = DEFAULT_PROJECT_ID,
    emulators: Sequence[str] = _ALL_EMULATORS,
    datastore_port: int = DATASTORE_PORT,
    datastore_dir: Optional[str] = None,
    tasks_port: int = TASKS_PORT,
    task_target_port: Optional[int] = None,
    autodetect_task_port: bool = True,
    storage_port: int = STORAGE_PORT,
    storage_dir: Optional[str] = None,

):
    # This prevents restarting of the emulators when Django code reload kicks in
    if os.environ.get(DJANGO_AUTORELOAD_ENV) == 'true':
        return

    storage_dir = storage_dir or os.path.join(get_application_root(), ".storage")
    enable_test_environment_variables()

    if "datastore" in emulators:
        if not port_is_open(SERVICE_HOST, datastore_port):
            # If start_emulators is call explicitly passing the Datastore Emulator port
            # and the port is not available raise and Runtime exception.
            if datastore_port != DATASTORE_PORT:
                raise RuntimeError(f"Unable to start Cloud Datastore Emulator at port {datastore_port}.")
            else:
                datastore_port = get_next_available_port(SERVICE_HOST, datastore_port)

        os.environ["DATASTORE_EMULATOR_HOST"] = f"{SERVICE_HOST}:{datastore_port}"
        os.environ["DATASTORE_PROJECT_ID"] = project_id

        # Start the cloud datastore emulator
        command = f"gcloud beta emulators datastore start --user-output-enabled=false --consistency=1.0 --quiet --project={project_id}"  # noqa
        command += f" --host-port={SERVICE_HOST}:{datastore_port}"

        if datastore_dir:
            command += " --data-dir=%s" % datastore_dir
        if not persist_data:
            command += " --no-store-on-disk"

        _ACTIVE_EMULATORS["datastore"] = _launch_process(command)
        _wait_for_datastore(datastore_port)

    if "tasks" in emulators:
        # If start_emulators is call explicitly passing the Cloud Task emulator port
        # and the port is not available raise and Runtime exception.
        if not port_is_open(SERVICE_HOST, tasks_port):
            if tasks_port != TASKS_PORT:
                raise RuntimeError(f"Unable to start Cloud Tasks Emulator at port {tasks_port}.")
            else:
                tasks_port = get_next_available_port(SERVICE_HOST, tasks_port)

        from djangae.tasks import cloud_tasks_location, cloud_tasks_parent_path, cloud_tasks_project
        default_queue = "%s/queues/default" % cloud_tasks_parent_path()

        if task_target_port is None:
            if sys.argv[1] == "runserver" and autodetect_task_port:
                from django.core.management.commands.runserver import Command as RunserverCommand
                parser = RunserverCommand().create_parser('django', 'runserver')
                args = parser.parse_args(sys.argv[2:])
                if args.addrport:
                    task_target_port = args.addrport.split(":")[-1]
                else:
                    task_target_port = _DJANGO_DEFAULT_PORT
            else:
                task_target_port = _DJANGO_DEFAULT_PORT

        command = "gcloud-tasks-emulator start -q --port=%s --target-port=%s --default-queue=%s" % (
            tasks_port, task_target_port, default_queue
        )

        # If the project contains a queue.yaml, pass it to the Tasks Emulator so that those queues
        # can be created (needs version >= 0.4.0)
        queue_yaml = os.path.join(get_application_root(), "queue.yaml")
        if os.path.exists(queue_yaml):
            command += " --queue-yaml=%s --queue-yaml-project=%s --queue-yaml-location=%s" % (
                queue_yaml, cloud_tasks_project(), cloud_tasks_location()
            )

        os.environ["TASKS_EMULATOR_HOST"] = f"{SERVICE_HOST}:{tasks_port}"
        _ACTIVE_EMULATORS["tasks"] = _launch_process(command)
        _wait_for_tasks(tasks_port)

    if "storage" in emulators:
        # If start_emulators is call explicitly passing the Cloud Storage emulator port
        # and the port is not available raise and Runtime exception.
        if not port_is_open(SERVICE_HOST, storage_port):
            if storage_port != STORAGE_PORT:
                raise RuntimeError(f"Unable to start Cloud Storage Emulator at port {storage_port}.")
            else:
                storage_port = get_next_available_port(SERVICE_HOST, storage_port)

        os.environ["STORAGE_EMULATOR_HOST"] = f"http://{SERVICE_HOST}:{storage_port}"
        command = "gcloud-storage-emulator start -q --port=%s --default-bucket=%s" % (
            storage_port, DEFAULT_BUCKET)

        if not persist_data:
            command += " --no-store-on-disk"

        _ACTIVE_EMULATORS["storage"] = _launch_process(command)
        _wait_for_storage(storage_port)
Beispiel #18
0
    def inner_run(self, *args, **options):
        import sys

        shutdown_message = options.get('shutdown_message', '')

        quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'

        from djangae.environment import get_application_root
        from djangae.sandbox import _find_sdk_from_python_path
        from djangae.blobstore_service import stop_blobstore_service

        from django.conf import settings
        from django.utils import translation

        stop_blobstore_service()

        # Check for app.yaml
        expected_path = os.path.join(get_application_root(), "app.yaml")
        if not os.path.exists(expected_path):
            sys.stderr.write("Unable to find app.yaml at '%s'\n" % expected_path)
            sys.exit(1)

        self.stdout.write("Validating models...\n\n")
        self.check(display_num_errors=True)
        self.stdout.write((
            "%(started_at)s\n"
            "Django version %(version)s, using settings %(settings)r\n"
            "Starting development server at http://%(addr)s:%(port)s/\n"
            "Quit the server with %(quit_command)s.\n"
        ) % {
            "started_at": datetime.now().strftime('%B %d, %Y - %X'),
            "version": self.get_version(),
            "settings": settings.SETTINGS_MODULE,
            "addr": self._raw_ipv6 and '[%s]' % self.addr or self.addr,
            "port": self.port,
            "quit_command": quit_command,
        })
        sys.stdout.write("\n")
        sys.stdout.flush()

        # django.core.management.base forces the locale to en-us. We should
        # set it up correctly for the first request (particularly important
        # in the "--noreload" case).
        translation.activate(settings.LANGUAGE_CODE)

        # Will have been set by setup_paths
        sdk_path = _find_sdk_from_python_path()

        from google.appengine.tools.devappserver2 import devappserver2
        from google.appengine.tools.devappserver2 import python_runtime

        from djangae import sandbox

        # Add any additional modules specified in the settings
        additional_modules = getattr(settings, "DJANGAE_ADDITIONAL_MODULES", [])
        if additional_modules:
            sandbox._OPTIONS.config_paths.extend(additional_modules)

        if int(self.port) != sandbox._OPTIONS.port or additional_modules:
            # Override the port numbers
            sandbox._OPTIONS.port = int(self.port)
            sandbox._OPTIONS.admin_port = int(self.port) + len(additional_modules) + 1
            sandbox._OPTIONS.api_port = int(self.port) + len(additional_modules) + 2

        if self.addr != sandbox._OPTIONS.host:
            sandbox._OPTIONS.host = sandbox._OPTIONS.admin_host = sandbox._OPTIONS.api_host = self.addr

        # Extra options for `dev_appserver.py`
        for param, value in self.gae_options.items():
            setattr(sandbox._OPTIONS, param, value)

        # External port is a new flag introduced in 1.9.19
        current_version = _VersionList(GetVersionObject()['release'])
        if current_version >= _VersionList('1.9.19'):
            sandbox._OPTIONS.external_port = None

        sandbox._OPTIONS.automatic_restart = self.use_reloader

        if sandbox._OPTIONS.host == "127.0.0.1" and os.environ["HTTP_HOST"].startswith("localhost"):
            hostname = "localhost"
            sandbox._OPTIONS.host = "localhost"
        else:
            hostname = sandbox._OPTIONS.host

        os.environ["HTTP_HOST"] = "%s:%s" % (hostname, sandbox._OPTIONS.port)
        os.environ['SERVER_NAME'] = os.environ['HTTP_HOST'].split(':', 1)[0]
        os.environ['SERVER_PORT'] = os.environ['HTTP_HOST'].split(':', 1)[1]
        os.environ['DEFAULT_VERSION_HOSTNAME'] = '%s:%s' % (os.environ['SERVER_NAME'], os.environ['SERVER_PORT'])

        from google.appengine.api.appinfo import EnvironmentVariables

        class NoConfigDevServer(devappserver2.DevelopmentServer):
            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

                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

        from google.appengine.tools.devappserver2 import module

        def fix_watcher_files(regex):
            """ Monkeypatch dev_appserver's file watcher to ignore any unwanted dirs or files. """
            from google.appengine.tools.devappserver2 import watcher_common
            watcher_common._IGNORED_REGEX = regex
            watcher_common.ignore_file = ignore_file
            watcher_common.skip_ignored_dirs = skip_ignored_dirs

        regex = sandbox._CONFIG.modules[0].skip_files
        if regex:
            fix_watcher_files(regex)

        def logging_wrapper(func):
            """
                Changes logging to use the DJANGO_COLORS settings
            """
            def _wrapper(level, format, *args, **kwargs):
                if args and len(args) == 1 and isinstance(args[0], dict):
                    args = args[0]
                    status = str(args.get("status", 200))
                else:
                    status = "200"

                try:
                    msg = format % args
                except UnicodeDecodeError:
                    msg += "\n" # This is what Django does in WSGIRequestHandler.log_message

                # Utilize terminal colors, if available
                if status[0] == '2':
                    # Put 2XX first, since it should be the common case
                    msg = self.style.HTTP_SUCCESS(msg)
                elif status[0] == '1':
                    msg = self.style.HTTP_INFO(msg)
                elif status == '304':
                    msg = self.style.HTTP_NOT_MODIFIED(msg)
                elif status[0] == '3':
                    msg = self.style.HTTP_REDIRECT(msg)
                elif status == '404':
                    msg = self.style.HTTP_NOT_FOUND(msg)
                elif status[0] == '4':
                    # 0x16 = Handshake, 0x03 = SSL 3.0 or TLS 1.x
                    if status.startswith(str('\x16\x03')):
                        msg = ("You're accessing the development server over HTTPS, "
                            "but it only supports HTTP.\n")
                    msg = self.style.HTTP_BAD_REQUEST(msg)
                else:
                    # Any 5XX, or any other response
                    msg = self.style.HTTP_SERVER_ERROR(msg)

                return func(level, msg)
            return _wrapper

        module.logging.log = logging_wrapper(module.logging.log)

        python_runtime._RUNTIME_PATH = os.path.join(sdk_path, '_python_runtime.py')
        python_runtime._RUNTIME_ARGS = [sys.executable, python_runtime._RUNTIME_PATH]

        dev_server = NoConfigDevServer()

        try:
            dev_server.start(sandbox._OPTIONS)
            try:
                shutdown.wait_until_shutdown()
            except KeyboardInterrupt:
                pass
        finally:
            dev_server.stop()


        if shutdown_message:
            sys.stdout.write(shutdown_message)

        return
Beispiel #19
0
    def inner_run(self, *args, **options):
        import sys

        shutdown_message = options.get('shutdown_message', '')

        quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'

        from djangae.environment import get_application_root
        from djangae.sandbox import _find_sdk_from_python_path
        from djangae.blobstore_service import stop_blobstore_service

        from django.conf import settings
        from django.utils import translation

        stop_blobstore_service()

        # Check for app.yaml
        expected_path = os.path.join(get_application_root(), "app.yaml")
        if not os.path.exists(expected_path):
            sys.stderr.write("Unable to find app.yaml at '%s'\n" % expected_path)
            sys.exit(1)

        self.stdout.write("Validating models...\n\n")
        self.check(display_num_errors=True)
        self.stdout.write((
            "%(started_at)s\n"
            "Django version %(version)s, using settings %(settings)r\n"
            "Starting development server at http://%(addr)s:%(port)s/\n"
            "Quit the server with %(quit_command)s.\n"
        ) % {
            "started_at": datetime.now().strftime('%B %d, %Y - %X'),
            "version": self.get_version(),
            "settings": settings.SETTINGS_MODULE,
            "addr": self._raw_ipv6 and '[%s]' % self.addr or self.addr,
            "port": self.port,
            "quit_command": quit_command,
        })
        sys.stdout.write("\n")
        sys.stdout.flush()

        # django.core.management.base forces the locale to en-us. We should
        # set it up correctly for the first request (particularly important
        # in the "--noreload" case).
        translation.activate(settings.LANGUAGE_CODE)

        # Will have been set by setup_paths
        sdk_path = _find_sdk_from_python_path()

        from google.appengine.tools.devappserver2 import devappserver2
        from google.appengine.tools.devappserver2 import python_runtime

        from djangae import sandbox

        # Add any additional modules specified in the settings
        additional_modules = getattr(settings, "DJANGAE_ADDITIONAL_MODULES", [])
        if additional_modules:
            sandbox._OPTIONS.config_paths.extend(additional_modules)

        if int(self.port) != sandbox._OPTIONS.port or additional_modules:
            # Override the port numbers
            sandbox._OPTIONS.port = int(self.port)
            sandbox._OPTIONS.admin_port = int(self.port) + len(additional_modules) + 1
            sandbox._OPTIONS.api_port = int(self.port) + len(additional_modules) + 2

        if self.addr != sandbox._OPTIONS.host:
            sandbox._OPTIONS.host = sandbox._OPTIONS.admin_host = sandbox._OPTIONS.api_host = self.addr

        # Extra options for `dev_appserver.py`
        for param, value in self.gae_options.items():
            setattr(sandbox._OPTIONS, param, value)

        # External port is a new flag introduced in 1.9.19
        current_version = _VersionList(GetVersionObject()['release'])
        if current_version >= _VersionList('1.9.19') or \
                current_version == sandbox.TEMP_1_9_49_VERSION_NO:
            sandbox._OPTIONS.external_port = None

        # Apply equivalent options for Django args
        sandbox._OPTIONS.automatic_restart = self.use_reloader
        sandbox._OPTIONS.threadsafe_override = self.use_threading

        if sandbox._OPTIONS.host == "127.0.0.1" and os.environ["HTTP_HOST"].startswith("localhost"):
            hostname = "localhost"
            sandbox._OPTIONS.host = "localhost"
        else:
            hostname = sandbox._OPTIONS.host

        os.environ["HTTP_HOST"] = "%s:%s" % (hostname, sandbox._OPTIONS.port)
        os.environ['SERVER_NAME'] = os.environ['HTTP_HOST'].split(':', 1)[0]
        os.environ['SERVER_PORT'] = os.environ['HTTP_HOST'].split(':', 1)[1]
        os.environ['DEFAULT_VERSION_HOSTNAME'] = '%s:%s' % (os.environ['SERVER_NAME'], os.environ['SERVER_PORT'])

        from google.appengine.api.appinfo import EnvironmentVariables

        class NoConfigDevServer(devappserver2.DevelopmentServer):
            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

        from google.appengine.tools.devappserver2 import module

        def fix_watcher_files(regex):
            """ Monkeypatch dev_appserver's file watcher to ignore any unwanted dirs or files. """
            from google.appengine.tools.devappserver2 import watcher_common
            watcher_common._IGNORED_REGEX = regex
            watcher_common.ignore_file = ignore_file
            watcher_common.skip_ignored_dirs = skip_ignored_dirs

        regex = sandbox._CONFIG.modules[0].skip_files
        if regex:
            fix_watcher_files(regex)

        def logging_wrapper(func):
            """
                Changes logging to use the DJANGO_COLORS settings
            """
            def _wrapper(level, format, *args, **kwargs):
                if args and len(args) == 1 and isinstance(args[0], dict):
                    args = args[0]
                    status = str(args.get("status", 200))
                else:
                    status = "200"

                try:
                    msg = format % args
                except UnicodeDecodeError:
                    msg += "\n" # This is what Django does in WSGIRequestHandler.log_message

                # Utilize terminal colors, if available
                if status[0] == '2':
                    # Put 2XX first, since it should be the common case
                    msg = self.style.HTTP_SUCCESS(msg)
                elif status[0] == '1':
                    msg = self.style.HTTP_INFO(msg)
                elif status == '304':
                    msg = self.style.HTTP_NOT_MODIFIED(msg)
                elif status[0] == '3':
                    msg = self.style.HTTP_REDIRECT(msg)
                elif status == '404':
                    msg = self.style.HTTP_NOT_FOUND(msg)
                elif status[0] == '4':
                    # 0x16 = Handshake, 0x03 = SSL 3.0 or TLS 1.x
                    if status.startswith(str('\x16\x03')):
                        msg = ("You're accessing the development server over HTTPS, "
                            "but it only supports HTTP.\n")
                    msg = self.style.HTTP_BAD_REQUEST(msg)
                else:
                    # Any 5XX, or any other response
                    msg = self.style.HTTP_SERVER_ERROR(msg)

                return func(level, msg)
            return _wrapper

        module.logging.log = logging_wrapper(module.logging.log)

        python_runtime._RUNTIME_PATH = os.path.join(sdk_path, '_python_runtime.py')
        python_runtime._RUNTIME_ARGS = [sys.executable, python_runtime._RUNTIME_PATH]

        dev_server = NoConfigDevServer()

        try:
            dev_server.start(sandbox._OPTIONS)
            try:
                shutdown.wait_until_shutdown()
            except KeyboardInterrupt:
                pass
        finally:
            dev_server.stop()


        if shutdown_message:
            sys.stdout.write(shutdown_message)

        return
Beispiel #20
0
import os
import re
import sys
import argparse

import djangae.sandbox as sandbox
from djangae import environment

DEFAULTS = {
    "storage_path": os.path.join(environment.get_application_root(),
                                 ".storage"),
    "port": 8000,
    "admin_port": 8001,
    "api_port": 8002,
    "automatic_restart": "True",
    "allow_skipped_files": "True",
}


def execute_from_command_line(argv=None, **sandbox_overrides):
    """Wraps Django's `execute_from_command_line` to initialize a djangae
    sandbox before running a management command.
    """
    argv = argv or sys.argv[:]

    djangae_parser = argparse.ArgumentParser(description='Djangae arguments',
                                             add_help=False)
    djangae_parser.add_argument('--sandbox',
                                default=sandbox.LOCAL,
                                choices=sandbox.SANDBOXES.keys())
    djangae_parser.add_argument('--app_id',
Beispiel #21
0
def start_emulators(
    persist_data: bool,
    project_id: str = DEFAULT_PROJECT_ID,
    emulators: Sequence[str] = _ALL_EMULATORS,
    datastore_port: int = DEFAULT_DATASTORE_PORT,
    datastore_dir: Optional[str] = None,
    tasks_port: int = DEFAULT_TASKS_PORT,
    task_target_port: Optional[int] = None,
    task_queue_yaml: Optional[str] = None,
    autodetect_task_port: bool = True,
    storage_port: int = DEFAULT_STORAGE_PORT,
    storage_dir: Optional[str] = None,
):
    # This prevents restarting of the emulators when Django code reload kicks in
    if os.environ.get(DJANGO_AUTORELOAD_ENV) == 'true':
        return

    # If storage_dir and datastore_dir are specified, we just
    # use them verbatim, otherwise we do some guesswork
    if not (storage_dir and datastore_dir):
        # sys.path[0] is nearly always the parent path of the
        # executed script (e.g. manage.py)
        base_path = sys.path[0]

        # Fall-back to the application root with a warning
        if not base_path:
            logging.warn(
                "Unable to determine script path, using "
                "application root for storage directories"
            )
            base_path = get_application_root()

        storage_dir = storage_dir or os.path.join(base_path, ".clouddata", "storage")
        datastore_dir = datastore_dir or os.path.join(base_path, ".clouddata", "datastore")

    os.makedirs(storage_dir, exist_ok=True)
    os.makedirs(datastore_dir, exist_ok=True)

    enable_test_environment_variables()

    if "datastore" in emulators:
        if not port_is_open(SERVICE_HOST, datastore_port):
            # If start_emulators is call explicitly passing the Datastore Emulator port
            # and the port is not available raise and Runtime exception.
            if datastore_port != DEFAULT_DATASTORE_PORT:
                raise RuntimeError(f"Unable to start Cloud Datastore Emulator at port {datastore_port}.")
            else:
                datastore_port = get_next_available_port(SERVICE_HOST, datastore_port)

        os.environ["DATASTORE_EMULATOR_HOST"] = f"{SERVICE_HOST}:{datastore_port}"
        os.environ["DATASTORE_PROJECT_ID"] = project_id

        # Start the cloud datastore emulator
        command = f"gcloud beta emulators datastore start --user-output-enabled=false --consistency=1.0 --quiet --project={project_id}"  # noqa
        command += f" --host-port={SERVICE_HOST}:{datastore_port}"

        if datastore_dir:
            command += " --data-dir=%s" % datastore_dir
        if not persist_data:
            command += " --no-store-on-disk"

        _ACTIVE_EMULATORS["datastore"] = _launch_process(command)
        _wait_for_datastore(datastore_port)

    if "tasks" in emulators:
        # If start_emulators is call explicitly passing the Cloud Task emulator port
        # and the port is not available raise and Runtime exception.
        if not port_is_open(SERVICE_HOST, tasks_port):
            if tasks_port != DEFAULT_TASKS_PORT:
                raise RuntimeError(f"Unable to start Cloud Tasks Emulator at port {tasks_port}.")
            else:
                tasks_port = get_next_available_port(SERVICE_HOST, tasks_port)

        from djangae.tasks import cloud_tasks_location, cloud_tasks_parent_path, cloud_tasks_project
        default_queue = "%s/queues/default" % cloud_tasks_parent_path()

        if task_target_port is None:
            if sys.argv[1] == "runserver" and autodetect_task_port:
                from django.core.management.commands.runserver import Command as RunserverCommand
                parser = RunserverCommand().create_parser('django', 'runserver')
                args = parser.parse_args(sys.argv[2:])
                if args.addrport:
                    task_target_port = args.addrport.split(":")[-1]
                else:
                    task_target_port = _DJANGO_DEFAULT_PORT
            else:
                task_target_port = _DJANGO_DEFAULT_PORT

        command = "gcloud-tasks-emulator start -q --port=%s --target-port=%s --default-queue=%s" % (
            tasks_port, task_target_port, default_queue
        )

        # If the project contains a queue.yaml, pass it to the Tasks Emulator so that those queues
        # can be created (needs version >= 0.4.0)
        if task_queue_yaml and os.path.exists(task_queue_yaml):
            command += " --queue-yaml=%s --queue-yaml-project=%s --queue-yaml-location=%s" % (
                task_queue_yaml, cloud_tasks_project(), cloud_tasks_location()
            )
        elif task_queue_yaml:
            logger.warn("task_queue_yaml was passed, but the file does not exist. Ignoring.")

        os.environ["TASKS_EMULATOR_HOST"] = f"{SERVICE_HOST}:{tasks_port}"
        _ACTIVE_EMULATORS["tasks"] = _launch_process(command)
        _wait_for_tasks(tasks_port)

    if "storage" in emulators:
        # If start_emulators is call explicitly passing the Cloud Storage emulator port
        # and the port is not available raise and Runtime exception.
        if not port_is_open(SERVICE_HOST, storage_port):
            if storage_port != DEFAULT_STORAGE_PORT:
                raise RuntimeError(f"Unable to start Cloud Storage Emulator at port {storage_port}.")
            else:
                storage_port = get_next_available_port(SERVICE_HOST, storage_port)

        os.environ["STORAGE_EMULATOR_HOST"] = f"http://{SERVICE_HOST}:{storage_port}"
        command = "gcloud-storage-emulator start -q --port=%s --default-bucket=%s" % (
            storage_port, DEFAULT_BUCKET)

        if storage_dir:
            command += " --data-dir=%s" % storage_dir

        if not persist_data:
            command += " --no-store-on-disk"

        _ACTIVE_EMULATORS["storage"] = _launch_process(command)
        _wait_for_storage(storage_port)