示例#1
0
def test_get_flow_returns_flow():
    with tempfile.TemporaryDirectory() as tmpdir:
        storage = Local(directory=tmpdir)
        f = Flow("test")
        loc = storage.add_flow(f)
        runner = storage.get_flow(loc)
        assert runner == f
示例#2
0
def test_k8s_agent_deploy_flow_raises(monkeypatch, cloud_api):
    batch_client = MagicMock()
    monkeypatch.setattr("kubernetes.client.BatchV1Api",
                        MagicMock(return_value=batch_client))

    core_client = MagicMock()
    core_client.list_namespaced_pod.return_value = MagicMock(items=[])
    monkeypatch.setattr("kubernetes.client.CoreV1Api",
                        MagicMock(return_value=core_client))

    get_jobs = MagicMock(return_value=[])
    monkeypatch.setattr(
        "prefect.agent.kubernetes.agent.KubernetesAgent.manage_jobs",
        get_jobs,
    )

    agent = KubernetesAgent()
    with pytest.raises(ValueError):
        agent.deploy_flow(flow_run=GraphQLResult({
            "flow":
            GraphQLResult({
                "storage": Local().serialize(),
                "id": "id",
                "environment": LocalEnvironment().serialize(),
                "core_version": "0.13.0",
            }),
            "id":
            "id",
        }))

    assert not agent.batch_client.create_namespaced_job.called
示例#3
0
    async def flow(self, project_id, tmpdir):
        """
        A simple diamond flow
        """
        @prefect.task
        def numbers():
            return [1, 2, 3]

        @prefect.task
        def add(x, y):
            return x + y

        with prefect.Flow(
                "simple map",
                run_config=prefect.run_configs.LocalRun(),
                storage=Local(directory=tmpdir),
        ) as flow:
            flow.numbers1 = numbers()
            flow.numbers2 = numbers()
            flow.add = add.map(flow.numbers1, flow.numbers2)

        add_state_handler(flow)

        with set_temporary_config(key="dev", value=True):
            flow.server_id = await api.flows.create_flow(
                project_id=project_id,
                serialized_flow=flow.serialize(build=True))

        return flow
示例#4
0
    async def flow(self, project_id, tmpdir):
        """
        A simple diamond flow
        """
        @prefect.task
        def numbers():
            return [1, 2, 3]

        @prefect.task
        def add(x):
            if x == 2:
                raise prefect.engine.signals.FAIL("Don't run for 2")
            elif not isinstance(x, int):
                return -99
            return x + 10

        with prefect.Flow(
                "simple map",
                run_config=prefect.run_configs.LocalRun(),
                storage=Local(directory=tmpdir),
        ) as flow:
            flow.numbers = numbers()
            flow.add1 = add.map(flow.numbers)
            flow.add2 = add.map(flow.add1)
            flow.add2.trigger = prefect.triggers.all_finished

        add_state_handler(flow)

        with set_temporary_config(key="dev", value=True):
            flow.server_id = await api.flows.create_flow(
                project_id=project_id,
                serialized_flow=flow.serialize(build=True))

        return flow
示例#5
0
    async def flow(self, project_id, tmpdir):
        """
        A simple diamond flow
        """
        @prefect.task
        def numbers():
            return [1, 2, 3]

        @prefect.task
        def add(x):
            return x + 1

        @prefect.task
        def get_sum(x):
            return sum(x)

        with prefect.Flow(
                "simple reduce",
                environment=LocalEnvironment(),
                storage=Local(directory=tmpdir),
        ) as flow:
            flow.numbers = numbers()
            flow.add = add.map(flow.numbers)
            flow.sum = get_sum(flow.add)

        add_state_handler(flow)

        with set_temporary_config(key="dev", value=True):
            flow.server_id = await api.flows.create_flow(
                project_id=project_id,
                serialized_flow=flow.serialize(build=True))

        return flow
示例#6
0
def test_local_agent_deploy_run_config_missing_working_dir(monkeypatch, tmpdir):
    popen = MagicMock()
    monkeypatch.setattr("prefect.agent.local.agent.Popen", popen)

    working_dir = str(tmpdir.join("missing"))

    agent = LocalAgent()

    with pytest.raises(ValueError, match="nonexistent `working_dir`"):
        agent.deploy_flow(
            flow_run=GraphQLResult(
                {
                    "id": "id",
                    "flow": {
                        "storage": Local().serialize(),
                        "id": "foo",
                        "core_version": "0.13.0",
                    },
                    "run_config": LocalRun(working_dir=working_dir).serialize(),
                },
            )
        )

    assert not popen.called
    assert not agent.processes
示例#7
0
    async def flow(self, project_id, tmpdir):
        """
        A simple diamond flow
        """
        @prefect.task
        def numbers():
            return [1, 2, 3]

        @prefect.task
        def add(x):
            if x == 2:
                raise prefect.engine.signals.FAIL("Don't run for 2")
            return x + 10

        with prefect.Flow(
                "simple map",
                environment=LocalEnvironment(),
                storage=Local(directory=tmpdir),
        ) as flow:
            flow.numbers = numbers()
            flow.add1 = add.map(flow.numbers)
            flow.add2 = add.map(flow.add1)

        add_state_handler(flow)

        with set_temporary_config(key="dev", value=True):
            flow.server_id = await api.flows.create_flow(
                project_id=project_id,
                serialized_flow=flow.serialize(build=True))

        return flow
示例#8
0
def test_local_agent_deploy_run_config_working_dir(monkeypatch, working_dir, tmpdir):
    popen = MagicMock()
    monkeypatch.setattr("prefect.agent.local.agent.Popen", popen)

    if working_dir is not None:
        working_dir = str(tmpdir)

    agent = LocalAgent()

    agent.deploy_flow(
        flow_run=GraphQLResult(
            {
                "id": "id",
                "flow": {
                    "storage": Local().serialize(),
                    "id": "foo",
                    "core_version": "0.13.0",
                },
                "run_config": LocalRun(working_dir=working_dir).serialize(),
            },
        )
    )

    assert popen.called
    assert len(agent.processes) == 1
    assert popen.call_args[1]["cwd"] == working_dir
示例#9
0
def test_local_agent_deploy_unsupported_run_config(monkeypatch):
    popen = MagicMock()
    monkeypatch.setattr("prefect.agent.local.agent.Popen", popen)

    agent = LocalAgent()

    with pytest.raises(
        TypeError,
        match="`run_config` of type `KubernetesRun`, only `LocalRun` is supported",
    ):
        agent.deploy_flow(
            flow_run=GraphQLResult(
                {
                    "id": "id",
                    "flow": {
                        "storage": Local().serialize(),
                        "id": "foo",
                        "core_version": "0.13.0",
                    },
                    "run_config": KubernetesRun().serialize(),
                },
            )
        )

    assert not popen.called
    assert len(agent.processes) == 0
示例#10
0
def configure_local():
    # Using Local
    flow.storage = Local(
        stored_as_script=True,
        path=
        "/home/steph/Code/steph-ben/fetch-with-prefect/config/laptop/simpleflow.py"
    )
示例#11
0
def test_docker_agent_deploy_flow_does_not_include_host_gateway_for_old_engine_versions(
        api, docker_engine_version):
    api.version.return_value = {"Version": docker_engine_version}

    run = UniversalRun()
    storage = Local()

    agent = DockerAgent()
    with pytest.warns(
            UserWarning,
            match=
        ("`host.docker.internal` could not be automatically resolved.*"
         f"feature is not supported on Docker Engine v{docker_engine_version}"
         ),
    ):
        agent.deploy_flow(flow_run=GraphQLResult({
            "flow":
            GraphQLResult({
                "id": "foo",
                "name": "flow-name",
                "storage": storage.serialize(),
                "core_version": "0.13.11",
            }),
            "run_config":
            run.serialize() if run else None,
            "id":
            "id",
            "name":
            "name",
        }))

    assert "extra_hosts" not in api.create_host_config.call_args[1]
示例#12
0
def test_add_flow_raises_if_name_conflict(tmpdir):
    storage = Local(directory=str(tmpdir))
    f = Flow("test")
    storage.add_flow(f)
    g = Flow("test")
    with pytest.raises(ValueError, match='name "test"'):
        storage.add_flow(g)
示例#13
0
def test_build_returns_self(tmpdir):
    s = Local(directory=str(tmpdir))
    assert s.build() is s

    f = Flow("test")
    s.add_flow(f)
    assert s.build() is s
示例#14
0
def load_flows_from_script(path: str) -> "List[prefect.Flow]":
    """Given a file path, load all flows found in the file"""
    # We use abs_path for everything but logging (logging the original
    # user-specified path provides a clearer message).
    abs_path = os.path.abspath(path)
    # Temporarily add the flow's local directory to `sys.path` so that local
    # imports work. This ensures that `sys.path` is the same as it would be if
    # the flow script was run directly (i.e. `python path/to/flow.py`).
    orig_sys_path = sys.path.copy()
    sys.path.insert(0, os.path.dirname(abs_path))
    try:
        with prefect.context({
                "loading_flow": True,
                "local_script_path": abs_path
        }):
            namespace = runpy.run_path(abs_path, run_name="<flow>")
    except Exception as exc:
        click.secho(f"Error loading {path!r}:", fg="red")
        log_exception(exc, 2)
        raise TerminalError
    finally:
        sys.path[:] = orig_sys_path

    flows = [f for f in namespace.values() if isinstance(f, prefect.Flow)]
    if flows:
        for f in flows:
            if f.storage is None:
                f.storage = Local(path=abs_path, stored_as_script=True)
    return flows
示例#15
0
def test_docker_agent_deploy_flow_storage_raises(monkeypatch, api):
    monkeypatch.setattr("prefect.agent.agent.Client", MagicMock())

    agent = DockerAgent()

    with pytest.raises(ValueError):
        agent.deploy_flow(
            flow_run=GraphQLResult(
                {
                    "flow": GraphQLResult(
                        {
                            "storage": Local().serialize(),
                            "id": "foo",
                            "environment": LocalEnvironment().serialize(),
                            "core_version": "0.13.0",
                        }
                    ),
                    "id": "id",
                    "name": "name",
                    "version": "version",
                }
            )
        )

    assert not api.pull.called
def test_docker_agent_deploy_flow_unsupported_run_config(api):
    agent = DockerAgent()

    with pytest.raises(
            TypeError,
            match=
            "`run_config` of type `LocalRun`, only `DockerRun` is supported",
    ):
        agent.deploy_flow(flow_run=GraphQLResult({
            "flow":
            GraphQLResult({
                "storage": Local().serialize(),
                "id": "foo",
                "name": "flow-name",
                "core_version": "0.13.0",
            }),
            "run_config":
            LocalRun().serialize(),
            "id":
            "id",
            "name":
            "name",
            "version":
            "version",
        }))

    assert not api.pull.called
def test_docker_agent_deploy_flow_no_pull_using_environment_metadata(api):
    agent = DockerAgent(no_pull=True)
    agent.deploy_flow(flow_run=GraphQLResult({
        "flow":
        GraphQLResult({
            "id":
            "foo",
            "name":
            "flow-name",
            "storage":
            Local().serialize(),
            "environment":
            LocalEnvironment(metadata={
                "image": "name:tag"
            }).serialize(),
            "core_version":
            "0.13.0",
        }),
        "id":
        "id",
        "name":
        "name",
    }))

    assert not api.pull.called
    assert api.create_container.called
    assert api.start.called
def test_docker_agent_deploy_flow_sets_container_name_with_slugify(
        api, run_name, container_name):
    """
    Asserts that the container name is set to the flow run name and that collisions with
    existing containers with the same name is handled by adding an index
    """

    agent = DockerAgent()
    agent.deploy_flow(flow_run=GraphQLResult({
        "flow":
        GraphQLResult({
            "id":
            "foo",
            "name":
            "flow-name",
            "storage":
            Local().serialize(),
            "environment":
            LocalEnvironment(metadata={
                "image": "repo/name:tag"
            }).serialize(),
            "core_version":
            "0.13.0",
        }),
        "id":
        "id",
        "name":
        run_name,
    }))

    assert api.create_container.call_args[1]["name"] == container_name
示例#19
0
 def get_run_task_kwargs(self,
                         run_config,
                         tenant_id: str = None,
                         taskdef=None,
                         **kwargs):
     agent = ECSAgent(**kwargs)
     if tenant_id:
         agent.client._get_auth_tenant = MagicMock(return_value=tenant_id)
     flow_run = GraphQLResult({
         "flow":
         GraphQLResult({
             "storage": Local().serialize(),
             "id": "flow-id",
             "version": 1,
             "name": "Test Flow",
             "core_version": "0.13.0",
         }),
         "run_config":
         run_config.serialize(),
         "id":
         "flow-run-id",
     })
     if taskdef is None:
         taskdef = agent.generate_task_definition(flow_run, run_config)
     return agent.get_run_task_kwargs(flow_run, run_config, taskdef)
def test_docker_agent_deploy_flow_uses_environment_metadata(api):
    agent = DockerAgent()
    agent.deploy_flow(flow_run=GraphQLResult({
        "flow":
        GraphQLResult({
            "id":
            "foo",
            "name":
            "flow-name",
            "storage":
            Local().serialize(),
            "environment":
            LocalEnvironment(metadata={
                "image": "repo/name:tag"
            }).serialize(),
            "core_version":
            "0.13.0",
        }),
        "id":
        "id",
        "name":
        "name",
    }))

    assert api.pull.called
    assert api.create_container.called
    assert api.start.called

    assert api.create_host_config.call_args[1]["auto_remove"] is True
    assert api.create_container.call_args[1][
        "command"] == "prefect execute flow-run"
    assert api.create_container.call_args[1]["host_config"][
        "AutoRemove"] is True
    assert api.start.call_args[1]["container"] == "container_id"
示例#21
0
def test_get_flow_image_raises_on_missing_info():
    flow = Flow(
        "test",
        environment=LocalEnvironment(),
        storage=Local(),
    )
    with pytest.raises(ValueError):
        get_flow_image(flow=flow)
示例#22
0
def test_get_flow_image_raises_on_missing_info():
    flow = Flow(
        "test",
        run_config=UniversalRun(),
        storage=Local(),
    )
    with pytest.raises(ValueError):
        get_flow_image(flow=flow)
示例#23
0
def test_add_flow_raises_if_name_conflict():
    with tempfile.TemporaryDirectory() as tmpdir:
        storage = Local(directory=tmpdir)
        f = Flow("test")
        res = storage.add_flow(f)
        g = Flow("test")
        with pytest.raises(ValueError, match='name "test"'):
            storage.add_flow(g)
示例#24
0
def test_add_flow_with_weird_name_is_cleaned(tmpdir):
    s = Local(directory=str(tmpdir))
    flow = Flow("WELL what do you know?!~? looks like a test!!!!")
    loc = s.add_flow(flow)
    assert "?" not in loc
    assert "!" not in loc
    assert " " not in loc
    assert "~" not in loc
示例#25
0
def test_create_local_storage_without_validation():
    storage = Local(directory="C:\\Users\\chris\\.prefect\\flows",
                    validate=False)
    assert storage
    assert storage.directory == "C:\\Users\\chris\\.prefect\\flows"

    assert isinstance(storage.result, LocalResult)
    assert storage.result.dir == storage.directory
示例#26
0
def test_build_returns_self():
    with tempfile.TemporaryDirectory() as tmpdir:
        s = Local(directory=tmpdir)
        assert s.build() is s

        f = Flow("test")
        s.add_flow(f)
        assert s.build() is s
示例#27
0
def test_get_flow_image_env_metadata():
    flow = Flow(
        "test",
        environment=LocalEnvironment(metadata={"image": "repo/name:tag"}),
        storage=Local(),
    )
    image = get_flow_image(flow=flow)
    assert image == "repo/name:tag"
示例#28
0
def test_get_flow_image_run_config():
    flow = Flow(
        "test",
        run_config=DockerRun(image="repo/name:tag"),
        storage=Local(),
    )
    image = get_flow_image(flow=flow)
    assert image == "repo/name:tag"
示例#29
0
def test_client_register_flow_id_output(
    patch_post, use_run_config, compressed, monkeypatch, capsys, cloud_api, tmpdir
):
    if compressed:
        response = {
            "data": {
                "project": [{"id": "proj-id"}],
                "create_flow_from_compressed_string": {"id": "long-id"},
                "flow_by_pk": {"flow_group_id": "fg-id"},
            }
        }
    else:
        response = {
            "data": {
                "project": [{"id": "proj-id"}],
                "create_flow": {"id": "long-id"},
                "flow_by_pk": {"flow_group_id": "fg-id"},
            }
        }
    patch_post(response)

    monkeypatch.setattr(
        "prefect.client.Client.get_default_tenant_slug", MagicMock(return_value="tslug")
    )

    with set_temporary_config(
        {
            "cloud.api": "http://my-cloud.foo",
            "cloud.auth_token": "secret_token",
            "backend": "cloud",
        }
    ):
        client = Client()

    labels = ["test1", "test2"]
    storage = Local(tmpdir)
    if use_run_config:
        flow = prefect.Flow(
            name="test", storage=storage, run_config=LocalRun(labels=labels)
        )
        flow.environment = None
    else:
        flow = prefect.Flow(
            name="test", storage=storage, environment=LocalEnvironment(labels=labels)
        )
    flow.result = flow.storage.result

    flow_id = client.register(
        flow,
        project_name="my-default-project",
        compressed=compressed,
        version_group_id=str(uuid.uuid4()),
    )
    assert flow_id == "long-id"

    captured = capsys.readouterr()
    assert "Flow URL: https://cloud.prefect.io/tslug/flow/fg-id\n" in captured.out
    assert f"Labels: {labels}" in captured.out
def test_docker_agent_deploy_flow_run_config(api, run_kind,
                                             has_docker_storage):
    if has_docker_storage:
        storage = Docker(registry_url="testing",
                         image_name="on-storage",
                         image_tag="tag")
        image = "testing/on-storage:tag"
    else:
        storage = Local()
        image = "on-run-config" if run_kind == "docker" else "prefecthq/prefect:0.13.11"

    if run_kind == "docker":
        env = {"TESTING": "VALUE"}
        host_config = {"auto_remove": False, "shm_size": "128m"}
        exp_host_config = {
            "auto_remove": False,
            "extra_hosts": {
                "host.docker.internal": "host-gateway"
            },
            "shm_size": "128m",
        }
        run = DockerRun(image=image, env=env, host_config=host_config)
    else:
        env = {}
        host_config = {}
        exp_host_config = {
            "auto_remove": True,
            "extra_hosts": {
                "host.docker.internal": "host-gateway"
            },
        }
        run = None if run_kind == "missing" else UniversalRun()

    agent = DockerAgent()
    agent.deploy_flow(flow_run=GraphQLResult({
        "flow":
        GraphQLResult({
            "id": "foo",
            "name": "flow-name",
            "storage": storage.serialize(),
            "core_version": "0.13.11",
        }),
        "run_config":
        run.serialize() if run else None,
        "id":
        "id",
        "name":
        "name",
    }))

    assert api.create_container.called
    assert api.create_container.call_args[0][0] == image
    res_env = api.create_container.call_args[1]["environment"]
    for k, v in env.items():
        assert res_env[k] == v
    res_host_config = api.create_host_config.call_args[1]
    for k, v in exp_host_config.items():
        assert res_host_config[k] == v