Ejemplo n.º 1
0
def test_generate_sample_service_not_found():
    schema = DummyApiSchema({}, DummyNaming("pkg_name"))
    sample = {"service": "Mollusc"}

    with pytest.raises(types.UnknownService):
        samplegen.generate_sample(
            sample,
            schema,
            env.get_template('examples/sample.py.j2'),
        )
def test_generate_sample_rpc_not_found():
    schema = DummyApiSchema(
        {"Mollusc": DummyService({})}, DummyNaming("pkg_name"))
    sample = {"service": "Mollusc", "rpc": "Classify"}

    with pytest.raises(types.RpcMethodNotFound):
        list(samplegen.generate_sample(sample, env, schema))
Ejemplo n.º 3
0
def test_generate_sample_rpc_not_found():
    schema = DummyApiSchema(
        {"Mollusc": DummyService(methods={}, client_name="ClassifyClient")},
        DummyNaming("pkg_name"))
    sample = {"service": "Mollusc", "rpc": "Classify"}

    with pytest.raises(types.RpcMethodNotFound):
        list(
            samplegen.generate_sample(
                sample, schema, env.get_template('examples/sample.py.j2')), )
Ejemplo n.º 4
0
def test_generate_sample_basic():
    # Note: the sample integration tests are needfully large
    # and difficult to eyeball parse. They are intended to be integration tests
    # that catch errors in behavior that is emergent from combining smaller features
    # or in features that are sufficiently small and trivial that it doesn't make sense
    # to have standalone tests.
    input_type = DummyMessage(
        type="REQUEST TYPE",
        fields={
            "classify_target":
            DummyField(message=DummyMessage(
                type="CLASSIFY TYPE",
                fields={
                    "video":
                    DummyField(message=DummyMessage(type="VIDEO TYPE"), ),
                    "location_annotation":
                    DummyField(message=DummyMessage(type="LOCATION TYPE"), )
                },
            ))
        })

    api_naming = naming.NewNaming(name="MolluscClient",
                                  namespace=("molluscs", "v1"))
    service = wrappers.Service(
        service_pb=namedtuple('service_pb', ['name'])('MolluscService'),
        methods={
            "Classify":
            DummyMethod(input=input_type,
                        output=message_factory("$resp.taxonomy"),
                        flattened_fields={
                            "classify_target":
                            DummyField(name="classify_target")
                        })
        },
        visible_resources={},
    )

    schema = DummyApiSchema(
        services={"animalia.mollusca.v1.Mollusc": service},
        naming=api_naming,
    )

    sample = {
        "service":
        "animalia.mollusca.v1.Mollusc",
        "rpc":
        "Classify",
        "id":
        "mollusc_classify_sync",
        "description":
        "Determine the full taxonomy of input mollusc",
        "request": [{
            "field": "classify_target.video",
            "value": "path/to/mollusc/video.mkv",
            "input_parameter": "video",
            "value_is_file": True
        }, {
            "field": "classify_target.location_annotation",
            "value": "New Zealand",
            "input_parameter": "location"
        }],
        "response": [{
            "print": ['Mollusc is a "%s"', "$resp.taxonomy"]
        }]
    }

    sample_str = samplegen.generate_sample(
        sample, schema, env.get_template('examples/sample.py.j2'))

    sample_id = ("mollusc_classify_sync")
    expected_str = '''# -*- coding: utf-8 -*-
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# DO NOT EDIT! This is a generated sample ("request",  "%s")
#
# To install the latest published package dependency, execute the following:
#   pip3 install molluscs-v1-molluscclient


# [START %s]
from google import auth
from google.auth import credentials
from molluscs.v1.molluscclient.services.mollusc_service import MolluscServiceClient

def sample_classify(video, location):
    """Determine the full taxonomy of input mollusc"""

    client = MolluscServiceClient(
        credentials=credentials.AnonymousCredentials(),
        transport="grpc",
    )

    classify_target = {}
    # video = "path/to/mollusc/video.mkv"
    with open(video, "rb") as f:
        classify_target["video"] = f.read()

    # location = "New Zealand"
    classify_target["location_annotation"] = location

 
 
    response = client.classify(classify_target=classify_target)
    print("Mollusc is a \\"{}\\"".format(response.taxonomy))
 

# [END %s]

def main():
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--video",
                        type=str,
                        default="path/to/mollusc/video.mkv")
    parser.add_argument("--location",
                        type=str,
                        default="New Zealand")
    args = parser.parse_args()

    sample_classify(args.video, args.location)


if __name__ == "__main__":
    main()
''' % (sample_id, sample_id, sample_id)

    assert sample_str == expected_str
Ejemplo n.º 5
0
    def _generate_samples_and_manifest(
            self, api_schema: api.API, index: snippet_index.SnippetIndex, sample_template: jinja2.Template, *, opts: Options) -> Tuple[Dict, snippet_index.SnippetIndex]:
        """Generate samples and samplegen manifest for the API.

        Arguments:
            api_schema (api.API): The schema for the API to which the samples belong.
            sample_template (jinja2.Template): The template to use to generate samples.
            opts (Options): Additional generator options.

        Returns:
            Tuple[Dict[str, CodeGeneratorResponse.File], snippet_index.SnippetIndex] : A dict mapping filepath to rendered file.
        """
        # The two-layer data structure lets us do two things:
        # * detect duplicate samples, which is an error
        # * detect distinct samples with the same ID, which are disambiguated
        id_to_hash_to_spec: DefaultDict[str,
                                        Dict[str, Any]] = defaultdict(dict)

        # Autogenerated sample specs
        autogen_specs: typing.List[typing.Dict[str, Any]] = []
        if opts.autogen_snippets:
            autogen_specs = list(
                samplegen.generate_sample_specs(api_schema, opts=opts))

        # Also process any handwritten sample specs
        handwritten_specs = samplegen.parse_handwritten_specs(
            self._sample_configs)

        sample_specs = autogen_specs + list(handwritten_specs)

        for spec in sample_specs:
            # Every sample requires an ID. This may be provided
            # by a samplegen config author.
            # If no ID is provided, fall back to the region tag.
            #
            # Ideally the sample author should pick a descriptive, unique ID,
            # but this may be impractical and can be error-prone.
            spec_hash = sha256(str(spec).encode("utf8")).hexdigest()[:8]
            sample_id = spec.get("id") or spec.get("region_tag") or spec_hash
            spec["id"] = sample_id

            hash_to_spec = id_to_hash_to_spec[sample_id]

            if spec_hash in hash_to_spec:
                raise DuplicateSample(
                    f"Duplicate samplegen spec found: {spec}")

            hash_to_spec[spec_hash] = spec

        out_dir = "samples/generated_samples"
        fpath_to_spec_and_rendered = {}
        for hash_to_spec in id_to_hash_to_spec.values():
            for spec_hash, spec in hash_to_spec.items():
                id_is_unique = len(hash_to_spec) == 1
                # The ID is used to generate the file name. It must be globally unique.
                if not id_is_unique:
                    spec["id"] += f"_{spec_hash}"

                sample, snippet_metadata = samplegen.generate_sample(
                    spec, api_schema, sample_template,)

                fpath = utils.to_snake_case(spec["id"]) + ".py"
                fpath_to_spec_and_rendered[os.path.join(out_dir, fpath)] = (
                    spec,
                    sample,
                )

                snippet_metadata.file = fpath
                snippet_metadata.title = fpath

                index.add_snippet(
                    snippet_index.Snippet(sample, snippet_metadata))

        output_files = {
            fname: CodeGeneratorResponse.File(
                content=formatter.fix_whitespace(sample), name=fname
            )
            for fname, (_, sample) in fpath_to_spec_and_rendered.items()
        }

        if index.metadata_index.snippets:
            # NOTE(busunkim): Not all fields are yet populated in the snippet metadata.
            # Expected filename: snippet_metadata_{apishortname}_{apiversion}.json
            snippet_metadata_path = str(pathlib.Path(
                out_dir) / f"snippet_metadata_{api_schema.naming.name}_{api_schema.naming.version}.json").lower()
            output_files[snippet_metadata_path] = CodeGeneratorResponse.File(
                content=formatter.fix_whitespace(index.get_metadata_json()), name=snippet_metadata_path)

        return output_files, index
Ejemplo n.º 6
0
def test_generate_sample_basic():
    # Note: the sample integration tests are needfully large
    # and difficult to eyeball parse. They are intended to be integration tests
    # that catch errors in behavior that is emergent from combining smaller features
    # or in features that are sufficiently small and trivial that it doesn't make sense
    # to have standalone tests.

    input_type = DummyMessage(
        type="REQUEST TYPE",
        fields={
            "classify_target":
            DummyField(message=DummyMessage(
                type="CLASSIFY TYPE",
                fields={
                    "video":
                    DummyField(message=DummyMessage(type="VIDEO TYPE"), ),
                    "location_annotation":
                    DummyField(message=DummyMessage(type="LOCATION TYPE"), )
                },
            ))
        },
        ident=DummyIdent(name="molluscs.v1.ClassifyRequest"))

    api_naming = naming.NewNaming(name="MolluscClient",
                                  namespace=("molluscs", "v1"))
    service = wrappers.Service(
        service_pb=namedtuple('service_pb', ['name'])('MolluscService'),
        methods={
            "Classify":
            DummyMethod(input=input_type,
                        output=message_factory("$resp.taxonomy"),
                        flattened_fields={
                            "classify_target":
                            DummyField(name="classify_target")
                        })
        },
        visible_resources={},
    )

    schema = DummyApiSchema(
        services={"animalia.mollusca.v1.Mollusc": service},
        naming=api_naming,
    )

    sample = {
        "service":
        "animalia.mollusca.v1.Mollusc",
        "rpc":
        "Classify",
        "id":
        "mollusc_classify_sync",
        "description":
        "Determine the full taxonomy of input mollusc",
        "request": [{
            "field": "classify_target.video",
            "value": "path/to/mollusc/video.mkv",
            "input_parameter": "video",
            "value_is_file": True
        }, {
            "field": "classify_target.location_annotation",
            "value": "New Zealand",
            "input_parameter": "location"
        }],
        "response": [{
            "print": ['Mollusc is a "%s"', "$resp.taxonomy"]
        }]
    }

    sample_str = samplegen.generate_sample(
        sample, schema, env.get_template('examples/sample.py.j2'))

    assert sample_str == golden_snippet("sample_basic.py")
Ejemplo n.º 7
0
def test_generate_sample_void_method():
    input_type = DummyMessage(
        type="REQUEST TYPE",
        fields={
            "classify_target":
            DummyField(message=DummyMessage(
                type="CLASSIFY TYPE",
                fields={
                    "video":
                    DummyField(message=DummyMessage(type="VIDEO TYPE"), ),
                    "location_annotation":
                    DummyField(message=DummyMessage(type="LOCATION TYPE"), )
                },
            ))
        },
        ident=DummyIdent(name="molluscs.v1.ClassifyRequest"))

    api_naming = naming.NewNaming(name="MolluscClient",
                                  namespace=("molluscs", "v1"))
    service = wrappers.Service(
        service_pb=namedtuple('service_pb', ['name'])('MolluscService'),
        methods={
            "Classify":
            DummyMethod(void=True,
                        input=input_type,
                        output=message_factory("$resp.taxonomy"),
                        flattened_fields={
                            "classify_target":
                            DummyField(name="classify_target")
                        })
        },
        visible_resources={},
    )

    schema = DummyApiSchema(
        services={"animalia.mollusca.v1.Mollusc": service},
        naming=api_naming,
    )

    sample = {
        "service":
        "animalia.mollusca.v1.Mollusc",
        "rpc":
        "Classify",
        "id":
        "mollusc_classify_sync",
        "description":
        "Determine the full taxonomy of input mollusc",
        "request": [{
            "field": "classify_target.video",
            "value": "path/to/mollusc/video.mkv",
            "input_parameter": "video",
            "value_is_file": True
        }, {
            "field": "classify_target.location_annotation",
            "value": "New Zealand",
            "input_parameter": "location"
        }]
    }

    sample_str = samplegen.generate_sample(
        sample, schema, env.get_template('examples/sample.py.j2'))

    assert sample_str == golden_snippet("sample_basic_void_method.py")
    def _generate_samples_and_manifest(
        self,
        api_schema: api.API,
        sample_template: jinja2.Template,
    ) -> Dict[str, CodeGeneratorResponse.File]:
        """Generate samples and samplegen manifest for the API.

        Arguments:
            api_schema (api.API): The schema for the API to which the samples belong.

        Returns:
            Dict[str, CodeGeneratorResponse.File]: A dict mapping filepath to rendered file.
        """
        # The two-layer data structure lets us do two things:
        # * detect duplicate samples, which is an error
        # * detect distinct samples with the same ID, which are disambiguated
        id_to_hash_to_spec: DefaultDict[str, Dict[str,
                                                  Any]] = defaultdict(dict)

        STANDALONE_TYPE = "standalone"
        for config_fpath in self._sample_configs:
            with open(config_fpath) as f:
                configs = yaml.safe_load_all(f.read())

            spec_generator = (
                spec for cfg in configs if is_valid_sample_cfg(cfg)
                for spec in cfg.get("samples", [])
                # If unspecified, assume a sample config describes a standalone.
                # If sample_types are specified, standalone samples must be
                # explicitly enabled.
                if STANDALONE_TYPE in spec.get("sample_type",
                                               [STANDALONE_TYPE]))

            for spec in spec_generator:
                # Every sample requires an ID, preferably provided by the
                # samplegen config author.
                # If no ID is provided, fall back to the region tag.
                # If there's no region tag, generate a unique ID.
                #
                # Ideally the sample author should pick a descriptive, unique ID,
                # but this may be impractical and can be error-prone.
                spec_hash = sha256(str(spec).encode("utf8")).hexdigest()[:8]
                sample_id = spec.get("id") or spec.get(
                    "region_tag") or spec_hash
                spec["id"] = sample_id

                hash_to_spec = id_to_hash_to_spec[sample_id]
                if spec_hash in hash_to_spec:
                    raise DuplicateSample(
                        f"Duplicate samplegen spec found: {spec}")

                hash_to_spec[spec_hash] = spec

        out_dir = "samples"
        fpath_to_spec_and_rendered = {}
        for hash_to_spec in id_to_hash_to_spec.values():
            for spec_hash, spec in hash_to_spec.items():
                id_is_unique = len(hash_to_spec) == 1
                # The ID is used to generate the file name and by sample tester
                # to link filenames to invoked samples. It must be globally unique.
                if not id_is_unique:
                    spec["id"] += f"_{spec_hash}"

                sample = samplegen.generate_sample(
                    spec,
                    api_schema,
                    sample_template,
                )

                fpath = spec["id"] + ".py"
                fpath_to_spec_and_rendered[os.path.join(out_dir, fpath)] = (
                    spec,
                    sample,
                )

        output_files = {
            fname: CodeGeneratorResponse.File(
                content=formatter.fix_whitespace(sample), name=fname)
            for fname, (_, sample) in fpath_to_spec_and_rendered.items()
        }

        # Only generate a manifest if we generated samples.
        if output_files:
            manifest_fname, manifest_doc = manifest.generate(
                ((fname, spec)
                 for fname, (spec, _) in fpath_to_spec_and_rendered.items()),
                api_schema,
            )

            manifest_fname = os.path.join(out_dir, manifest_fname)
            output_files[manifest_fname] = CodeGeneratorResponse.File(
                content=manifest_doc.render(), name=manifest_fname)

        return output_files
Ejemplo n.º 9
0
    def _generate_samples_and_manifest(self, api_schema: api.API,
                                       sample_template: jinja2.Template, *,
                                       opts: Options) -> Dict:
        """Generate samples and samplegen manifest for the API.

        Arguments:
            api_schema (api.API): The schema for the API to which the samples belong.
            sample_template (jinja2.Template): The template to use to generate samples.
            opts (Options): Additional generator options.

        Returns:
            Dict[str, CodeGeneratorResponse.File]: A dict mapping filepath to rendered file.
        """
        # The two-layer data structure lets us do two things:
        # * detect duplicate samples, which is an error
        # * detect distinct samples with the same ID, which are disambiguated
        id_to_hash_to_spec: DefaultDict[str, Dict[str,
                                                  Any]] = defaultdict(dict)

        # Autogenerated sample specs
        autogen_specs: typing.List[typing.Dict[str, Any]] = []
        if opts.autogen_snippets:
            autogen_specs = list(
                samplegen.generate_sample_specs(api_schema, opts=opts))

        # Also process any handwritten sample specs
        handwritten_specs = samplegen.parse_handwritten_specs(
            self._sample_configs)

        sample_specs = autogen_specs + list(handwritten_specs)

        for spec in sample_specs:
            # Every sample requires an ID. This may be provided
            # by a samplegen config author.
            # If no ID is provided, fall back to the region tag.
            #
            # Ideally the sample author should pick a descriptive, unique ID,
            # but this may be impractical and can be error-prone.
            spec_hash = sha256(str(spec).encode("utf8")).hexdigest()[:8]
            sample_id = spec.get("id") or spec.get("region_tag") or spec_hash
            spec["id"] = sample_id

            hash_to_spec = id_to_hash_to_spec[sample_id]

            if spec_hash in hash_to_spec:
                raise DuplicateSample(
                    f"Duplicate samplegen spec found: {spec}")

            hash_to_spec[spec_hash] = spec

        out_dir = "samples/generated_samples"
        fpath_to_spec_and_rendered = {}
        for hash_to_spec in id_to_hash_to_spec.values():
            for spec_hash, spec in hash_to_spec.items():
                id_is_unique = len(hash_to_spec) == 1
                # The ID is used to generate the file name. It must be globally unique.
                if not id_is_unique:
                    spec["id"] += f"_{spec_hash}"

                sample = samplegen.generate_sample(
                    spec,
                    api_schema,
                    sample_template,
                )

                fpath = utils.to_snake_case(spec["id"]) + ".py"
                fpath_to_spec_and_rendered[os.path.join(out_dir, fpath)] = (
                    spec,
                    sample,
                )

        output_files = {
            fname: CodeGeneratorResponse.File(
                content=formatter.fix_whitespace(sample), name=fname)
            for fname, (_, sample) in fpath_to_spec_and_rendered.items()
        }

        # TODO(busunkim): Re-enable manifest generation once metadata
        # format has been formalized.
        # https://docs.google.com/document/d/1ghBam8vMj3xdoe4xfXhzVcOAIwrkbTpkMLgKc9RPD9k/edit#heading=h.sakzausv6hue
        #
        # if output_files:

        # manifest_fname, manifest_doc = manifest.generate(
        #     (
        #         (fname, spec)
        #         for fname, (spec, _) in fpath_to_spec_and_rendered.items()
        #     ),
        #     api_schema,
        # )

        # manifest_fname = os.path.join(out_dir, manifest_fname)
        # output_files[manifest_fname] = CodeGeneratorResponse.File(
        #     content=manifest_doc.render(), name=manifest_fname
        # )

        return output_files
Ejemplo n.º 10
0
    def _generate_samples_and_manifest(
        self,
        api_schema: api.API
    ) -> Dict[str, CodeGeneratorResponse.File]:
        """Generate samples and samplegen manifest for the API.

        Arguments:
            api_schema (api.API): The schema for the API to which the samples belong.

        Returns:
            Dict[str, CodeGeneratorResponse.File]: A dict mapping filepath to rendered file.
        """
        id_to_samples: DefaultDict[str, List[Any]] = defaultdict(list)
        for config_fpath in self._sample_configs:
            with open(config_fpath) as f:
                configs = yaml.safe_load_all(f.read())

            spec_generator = (
                spec
                for cfg in configs if is_valid_sample_cfg(cfg)
                for spec in cfg.get("samples", [])
            )

            for spec in spec_generator:
                # Every sample requires an ID, preferably provided by the
                # samplegen config author.
                # If no ID is provided, fall back to the region tag.
                # If there's no region tag, generate a unique ID.
                #
                # Ideally the sample author should pick a descriptive, unique ID,
                # but this may be impractical and can be error-prone.
                sample_id = (spec.get("id")
                             or spec.get("region_tag")
                             or sha256(str(spec).encode('utf8')).hexdigest()[:8])

                spec["id"] = sample_id
                id_to_samples[sample_id].append(spec)

        out_dir = "samples"
        fpath_to_spec_and_rendered = {}
        for samples in id_to_samples.values():
            for spec in samples:
                id_is_unique = len(samples) == 1
                # The ID is used to generate the file name and by sample tester
                # to link filenames to invoked samples. It must be globally unique.
                if not id_is_unique:
                    spec_hash = sha256(
                        str(spec).encode('utf8')).hexdigest()[:8]
                    spec["id"] += f"_{spec_hash}"

                sample = samplegen.generate_sample(spec, self._env, api_schema)

                fpath = spec["id"] + ".py"
                fpath_to_spec_and_rendered[os.path.join(out_dir, fpath)] = (spec,
                                                                            sample)

        output_files = {
            fname: CodeGeneratorResponse.File(
                content=formatter.fix_whitespace(sample),
                name=fname
            )
            for fname, (_, sample) in fpath_to_spec_and_rendered.items()
        }

        # Only generate a manifest if we generated samples.
        if output_files:
            manifest_fname, manifest_doc = manifest.generate(
                ((fname, spec)
                 for fname, (spec, _) in fpath_to_spec_and_rendered.items()),
                api_schema
            )

            manifest_fname = os.path.join(out_dir, manifest_fname)
            output_files[manifest_fname] = CodeGeneratorResponse.File(
                content=manifest_doc.render(),
                name=manifest_fname
            )

        return output_files
def test_generate_sample_basic():
    # Note: the sample integration tests are needfully large
    # and difficult to eyeball parse. They are intended to be integration tests
    # that catch errors in behavior that is emergent from combining smaller features
    # or in features that are sufficiently small and trivial that it doesn't make sense
    # to have standalone tests.
    input_type = DummyMessage(
        type="REQUEST TYPE",
        fields={
            "classify_request": DummyField(
                message=DummyMessage(
                    type="CLASSIFY TYPE",
                    fields={
                        "video": DummyField(
                            message=DummyMessage(type="VIDEO TYPE"),
                        ),
                        "location_annotation": DummyField(
                            message=DummyMessage(type="LOCATION TYPE"),
                        )
                    },
                )
            )
        }
    )
    schema = DummyApiSchema(
        {
            "animalia.mollusca.v1.Mollusc": DummyService(
                {
                    "Classify": DummyMethod(
                        input=input_type,
                        output=message_factory("$resp.taxonomy")
                    )
                }
            )
        },
        DummyNaming("molluscs-v1-mollusc")
    )

    sample = {"service": "animalia.mollusca.v1.Mollusc",
              "rpc": "Classify",
              "id": "mollusc_classify_sync",
              "description": "Determine the full taxonomy of input mollusc",
              "request": [
                  {"field": "classify_request.video",
                   "value": "'path/to/mollusc/video.mkv'",
                   "input_parameter": "video",
                   "value_is_file": True},
                  {"field": "classify_request.location_annotation",
                   "value": "'New Zealand'",
                   "input_parameter": "location"}
              ],
              "response": [{"print": ["Mollusc is a %s", "$resp.taxonomy"]}]}

    sample_str = samplegen.generate_sample(
        sample, env, schema)

    sample_id = ("mollusc_classify_sync")
    expected_str = '''# TODO: add a copyright
# TODO: add a license
#
# DO NOT EDIT! This is a generated sample ("request",  "%s")
#
# To install the latest published package dependency, execute the following:
#   pip3 install molluscs-v1-mollusc


# [START %s]

def sample_classify(video, location):
    """Determine the full taxonomy of input mollusc"""

    client = mollusca_v1.MolluscClient()

    classify_request = {}
    # video = 'path/to/mollusc/video.mkv'
    with open(video, "rb") as f:
        classify_request["video"] = f.read()

    # location = 'New Zealand'
    classify_request["location_annotation"] = location


    response = client.classify(classify_request)

    print("Mollusc is a {}".format(response.taxonomy))

# [END %s]

def main():
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--video",
                        type=str,
                        default='path/to/mollusc/video.mkv')
    parser.add_argument("--location",
                        type=str,
                        default='New Zealand')
    args = parser.parse_args()

    sample_classify(args.video, args.location)


if __name__ == "__main__":
    main()
''' % (sample_id, sample_id, sample_id)

    assert sample_str == expected_str
def test_generate_sample_basic():
    # Note: the sample integration tests are needfully large
    # and difficult to eyeball parse. They are intended to be integration tests
    # that catch errors in behavior that is emergent from combining smaller features
    # or in features that are sufficiently small and trivial that it doesn't make sense
    # to have standalone tests.

    classify_target_field = DummyField(
        name="classify_target",
        type=DummyMessageTypePB(name="ClassifyTarget"),
        message=DummyMessage(
            type="CLASSIFY TYPE",
            fields={
                "video": DummyField(
                    type=DummyMessageTypePB(name="Video"),
                    message=DummyMessage(type="VIDEO TYPE"),
                ),
                "location_annotation": DummyField(
                    type=DummyMessageTypePB(name="Location"),
                    message=DummyMessage(type="LOCATION TYPE"),
                )
            },
        ),
        ident=DummyIdent(sphinx="molluscs_v1.ClassifyTarget")
    )

    input_type = DummyMessage(
        type="REQUEST TYPE",
        fields={
            "classify_target": classify_target_field
        },
        ident=DummyIdent(name="molluscs.v1.ClassifyRequest",
                         sphinx="molluscs_v1.classify_request")
    )

    output_type = DummyMessage(
        type="RESPONSE TYPE",
        fields={
            "classification": DummyField(
                type=DummyMessageTypePB(name="Classification"),
            )
        },
        ident=DummyIdent(sphinx="molluscs_v1.classification")
    )

    api_naming = naming.NewNaming(
        name="MolluscClient", namespace=("molluscs", "v1"))
    service = wrappers.Service(
        service_pb=namedtuple('service_pb', ['name'])('MolluscService'),
        methods={
            "Classify": DummyMethod(
                name="Classify",
                input=input_type,
                output=message_factory("$resp.taxonomy"),
                client_output=output_type,
                flattened_fields={
                    "classify_target": classify_target_field
                }
            )
        },
        visible_resources={},
    )

    schema = DummyApiSchema(
        services={"animalia.mollusca.v1.Mollusc": service},
        naming=api_naming,
    )

    sample = {"service": "animalia.mollusca.v1.Mollusc",
              "region_tag": "molluscs_generated_molluscs_v1_Mollusc_Classify_sync",
              "rpc": "Classify",
              "id": "mollusc_classify_sync",
              "description": "Determine the full taxonomy of input mollusc",
              "request": [
                  {"field": "classify_target.video",
                   "value": "path/to/mollusc/video.mkv",
                   "input_parameter": "video",
                   "value_is_file": True},
                  {"field": "classify_target.location_annotation",
                   "value": "New Zealand",
                   "input_parameter": "location"}
              ],
              "response": [{"print": ['Mollusc is a "%s"', "$resp.taxonomy"]}]}

    sample_str, metadata = samplegen.generate_sample(
        sample,
        schema,
        env.get_template('examples/sample.py.j2')
    )

    assert sample_str == golden_snippet("sample_basic.py")

    assert json_format.MessageToDict(metadata) == {
        'regionTag': 'molluscs_generated_molluscs_v1_Mollusc_Classify_sync',
        'description': 'Sample for Classify',
        'language': 'PYTHON',
        'clientMethod': {
            'shortName': 'classify',
            'fullName': 'molluscs.v1.molluscclient.MolluscServiceClient.classify',
            'parameters': [
                {'type': 'molluscs_v1.classify_request', 'name': 'request'},
                {'type': 'molluscs_v1.ClassifyTarget', 'name': 'classify_target'},
                {'type': 'google.api_core.retry.Retry', 'name': 'retry'},
                {'type': 'float', 'name': 'timeout'},
                {'type': 'Sequence[Tuple[str, str]', 'name': 'metadata'}
            ],
            'resultType': 'molluscs_v1.classification',
            'client': {
                'shortName': 'MolluscServiceClient',
                'fullName': 'molluscs.v1.molluscclient.MolluscServiceClient'
            },
            'method': {
                'shortName': 'Classify',
                'fullName': '.MolluscService.Classify',
                'service': {'shortName': 'MolluscService', 'fullName': '.MolluscService'}}
            },
        'canonical': True,
        'origin': 'API_DEFINITION'
    }
def test_generate_sample_void_method():
    classify_target_field = DummyField(
        name="classify_target",
        type=DummyMessageTypePB(name="ClassifyTarget"),
        message=DummyMessage(
            type="CLASSIFY TYPE",
            fields={
                "video": DummyField(
                    type=DummyMessageTypePB(name="Video"),
                    message=DummyMessage(type="VIDEO TYPE"),
                ),
                "location_annotation": DummyField(
                    type=DummyMessageTypePB(name="Location"),
                    message=DummyMessage(type="LOCATION TYPE"),
                )
            },
        ),
        ident=DummyIdent(sphinx="molluscs_v1.ClassifyTarget")
    )

    input_type = DummyMessage(
        type="REQUEST TYPE",
        fields={
            "classify_target": classify_target_field
        },
        ident=DummyIdent(name="molluscs.v1.ClassifyRequest",
                         sphinx="molluscs_v1.classify_request")
    )

    api_naming = naming.NewNaming(
        name="MolluscClient", namespace=("molluscs", "v1"))
    service = wrappers.Service(
        service_pb=namedtuple('service_pb', ['name'])('MolluscService'),
        methods={
            "Classify": DummyMethod(
                name="Classify",
                client_output=DummyIdent(name="classify", sphinx="classify"),
                void=True,
                input=input_type,
                output=message_factory("$resp.taxonomy"),
                flattened_fields={
                    "classify_target": classify_target_field,
                }
            )
        },
        visible_resources={},
    )

    schema = DummyApiSchema(
        services={"animalia.mollusca.v1.Mollusc": service},
        naming=api_naming,
    )

    sample = {"service": "animalia.mollusca.v1.Mollusc",
              "region_tag": "molluscs_generated_molluscs_v1_Mollusc_Classify_sync",
              "rpc": "Classify",
              "id": "mollusc_classify_sync",
              "description": "Determine the full taxonomy of input mollusc",
              "request": [
                  {"field": "classify_target.video",
                   "value": "path/to/mollusc/video.mkv",
                   "input_parameter": "video",
                   "value_is_file": True},
                  {"field": "classify_target.location_annotation",
                   "value": "New Zealand",
                   "input_parameter": "location"}
              ]}

    sample_str, metadata = samplegen.generate_sample(
        sample,
        schema,
        env.get_template('examples/sample.py.j2')
    )

    assert sample_str == golden_snippet("sample_basic_void_method.py")

    assert json_format.MessageToDict(metadata) == {
        'regionTag': 'molluscs_generated_molluscs_v1_Mollusc_Classify_sync',
        'description': 'Sample for Classify',
        'language': 'PYTHON',
        'clientMethod': {
            'shortName': 'classify',
            'fullName': 'molluscs.v1.molluscclient.MolluscServiceClient.classify',
            'parameters': [
                {'type': 'molluscs_v1.classify_request', 'name': 'request'},
                {'type': 'molluscs_v1.ClassifyTarget', 'name': 'classify_target'},
                {'type': 'google.api_core.retry.Retry', 'name': 'retry'},
                {'type': 'float', 'name': 'timeout'},
                {'type': 'Sequence[Tuple[str, str]', 'name': 'metadata'}
            ],
            'client': {
                'shortName': 'MolluscServiceClient',
                'fullName': 'molluscs.v1.molluscclient.MolluscServiceClient'
            },
            'method': {
                'shortName': 'Classify',
                'fullName': '.MolluscService.Classify',
                'service': {'shortName': 'MolluscService', 'fullName': '.MolluscService'}
            }
        },
        'canonical': True,
        'origin': 'API_DEFINITION'
    }