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))
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')), )
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
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
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")
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
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
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' }