def mock_generate_sample(*args, **kwargs): dummy_snippet_metadata = snippet_metadata_pb2.Snippet() dummy_snippet_metadata.client_method.method.service.short_name = args[0][ "service"].split(".")[-1] dummy_snippet_metadata.client_method.method.short_name = args[0]['rpc'] return "", dummy_snippet_metadata
def generate_sample(sample, api_schema, sample_template: jinja2.Template) -> Tuple[str, Any]: """Generate a standalone, runnable sample. Writing the rendered output is left for the caller. Args: sample (Any): A definition for a single sample. api_schema (api.API): The schema that defines the API to which the sample belongs. sample_template (jinja2.Template): The template representing a generic sample. Returns: Tuple(str, snippet_metadata_pb2.Snippet): The rendered sample. """ service_name = sample["service"] service = api_schema.services.get(service_name) if not service: raise types.UnknownService("Unknown service: {}", service_name) rpc_name = sample["rpc"] rpc = service.methods.get(rpc_name) if not rpc: raise types.RpcMethodNotFound( "Could not find rpc in service {}: {}".format( service_name, rpc_name) ) calling_form = types.CallingForm.method_default(rpc) v = Validator(rpc, api_schema) # Tweak some small aspects of the sample to set defaults for optional # fields, add fields that are required for the template, and so forth. v.preprocess_sample(sample, api_schema, rpc) sample["request"] = v.validate_and_transform_request( calling_form, sample["request"] ) v.validate_response(sample["response"]) # Snippet Metadata can't be fully filled out in any one function # In this function we add information from # the API schema and sample dictionary. snippet_metadata = snippet_metadata_pb2.Snippet() # type: ignore snippet_metadata.region_tag = sample["region_tag"] setattr(snippet_metadata.client_method, "async", sample["transport"] == api.TRANSPORT_GRPC_ASYNC) snippet_metadata.client_method.method.short_name = sample["rpc"] snippet_metadata.client_method.method.service.short_name = sample["service"].split( ".")[-1] return sample_template.render( sample=sample, imports=[], calling_form=calling_form, calling_form_enum=types.CallingForm, trim_blocks=True, lstrip_blocks=True, ), snippet_metadata
def test_add_snippet_no_matching_service(sample_str): snippet_metadata = snippet_metadata_pb2.Snippet() snippet_metadata.client_method.method.service.short_name = "Clam" snippet = snippet_index.Snippet(sample_str, snippet_metadata) # No 'Clam' service in API Schema index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( services={"Squid": DummyService(name="Squid", methods={})})) with pytest.raises(types.UnknownService): index.add_snippet(snippet)
def test_add_snippet_no_matching_rpc(sample_str): snippet_metadata = snippet_metadata_pb2.Snippet() snippet_metadata.client_method.method.service.short_name = "Squid" snippet_metadata.client_method.short_name = "classify" snippet = snippet_index.Snippet(sample_str, snippet_metadata) # No 'classify' method in 'Squid' service index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( services={"Squid": DummyService(name="Squid", methods={"list": None}) })) with pytest.raises(types.RpcMethodNotFound): index.add_snippet(snippet)
def test_get_metadata_json(sample_str): snippet_metadata = snippet_metadata_pb2.Snippet() snippet_metadata.client_method.method.service.short_name = "Squid" snippet_metadata.client_method.method.short_name = "classify" snippet = snippet_index.Snippet(sample_str, snippet_metadata) index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( services={ "Squid": DummyService(name="Squid", methods={"classify": DummyMethod()}) })) index.add_snippet(snippet) assert json.loads(index.get_metadata_json()) == { 'snippets': [{ 'clientMethod': { 'method': { 'shortName': 'classify', 'service': { 'shortName': 'Squid' } } }, 'segments': [{ 'end': 28, 'start': 2, 'type': 'FULL' }, { 'end': 28, 'start': 2, 'type': 'SHORT' }, { 'end': 8, 'start': 6, 'type': 'CLIENT_INITIALIZATION' }, { 'end': 22, 'start': 9, 'type': 'REQUEST_INITIALIZATION' }, { 'end': 25, 'start': 23, 'type': 'REQUEST_EXECUTION' }, { 'end': 29, 'start': 26, 'type': 'RESPONSE_HANDLING' }] }] }
def test_add_snippet_no_matching_service(sample_str): snippet_metadata = snippet_metadata_pb2.Snippet() snippet_metadata.client_method.method.service.short_name = "Clam" snippet = snippet_index.Snippet(sample_str, snippet_metadata) # No 'Clam' service in API Schema index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( services={"Squid": DummyService(name="Squid", methods={})}, naming=DummyNaming(proto_package="google.mollusca", warehouse_package_name="google-mollusca", version="v1"), )) with pytest.raises(types.UnknownService): index.add_snippet(snippet)
def test_add_snippet_no_matching_rpc(sample_str): snippet_metadata = snippet_metadata_pb2.Snippet() snippet_metadata.client_method.method.service.short_name = "Squid" snippet_metadata.client_method.short_name = "classify" snippet = snippet_index.Snippet(sample_str, snippet_metadata) # No 'classify' method in 'Squid' service index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( services={"Squid": DummyService(name="Squid", methods={"list": None})}, naming=DummyNaming(proto_package="google.mollusca", warehouse_package_name="google-mollusca", version="v1"), )) with pytest.raises(types.RpcMethodNotFound): index.add_snippet(snippet)
def test_add_and_get_snippet_sync(sample_str): snippet_metadata = snippet_metadata_pb2.Snippet() snippet_metadata.client_method.method.service.short_name = "Squid" snippet_metadata.client_method.method.short_name = "classify" snippet = snippet_index.Snippet(sample_str, snippet_metadata) index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( services={ "Squid": DummyService(name="Squid", methods={"classify": DummyMethod()}) })) index.add_snippet(snippet) index.get_snippet(service_name="Squid", rpc_name="classify")
def test_add_and_get_snippet_sync(sample_str): snippet_metadata = snippet_metadata_pb2.Snippet() snippet_metadata.client_method.method.service.short_name = "Squid" snippet_metadata.client_method.method.short_name = "classify" snippet = snippet_index.Snippet(sample_str, snippet_metadata) index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( services={ "Squid": DummyService(name="Squid", methods={"classify": DummyMethod()}) }, naming=DummyNaming(proto_package="google.mollusca", warehouse_package_name="google-mollusca", version="v1"), )) index.add_snippet(snippet) index.get_snippet(service_name="Squid", rpc_name="classify")
def test_snippet_init(sample_str): # We are not trying to exhaustively test the snippet metadata protobuf, # just checking that fields are not unset sample_metadata = snippet_metadata_pb2.Snippet(title="classify_squid.py") sample_metadata.language = snippet_metadata_pb2.Language.PYTHON snippet = snippet_index.Snippet(sample_str, sample_metadata) assert snippet.sample_str == sample_str # It's easier to eyeball diffs on the dictionary representation assert json_format.MessageToDict(snippet.metadata) == { "language": "PYTHON", "title": "classify_squid.py", "segments": [ { "end": 28, "start": 2, "type": "FULL" }, { "end": 28, "start": 2, "type": "SHORT" }, { "end": 8, "start": 6, "type": "CLIENT_INITIALIZATION" }, { "end": 22, "start": 9, "type": "REQUEST_INITIALIZATION" }, { "end": 25, "start": 23, "type": "REQUEST_EXECUTION" }, { "end": 29, "start": 26, "type": "RESPONSE_HANDLING" }, ] } # This is the same as the sample_str above, minus the # [START ...] # and # [END ...] lines expected_full_snipppet = """from molluscs.v1 import molluscclient def sample_classify(video, location): # Create a client client = molluscclient.MolluscServiceClient() # Initialize request argument(s) classify_target = molluscclient.ClassifyTarget() # 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 request = molluscclient.molluscs.v1.ClassifyRequest( classify_target=classify_target, ) # Make the request response = client.classify(request=request) # Handle the response print(f"Mollusc is a \"{response.taxonomy}\"") """ assert snippet.full_snippet == expected_full_snipppet
def test_get_metadata_json(sample_str): snippet_metadata = snippet_metadata_pb2.Snippet() snippet_metadata.client_method.method.service.short_name = "Squid" snippet_metadata.client_method.method.short_name = "classify" snippet = snippet_index.Snippet(sample_str, snippet_metadata) index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( services={ "Squid": DummyService(name="Squid", methods={"classify": DummyMethod()}) }, naming=DummyNaming(proto_package="google.mollusca", warehouse_package_name="google-mollusca", version="v1"), )) index.add_snippet(snippet) print(index.get_metadata_json()) assert json.loads(index.get_metadata_json()) == { "clientLibrary": { "apis": [{ "id": "google.mollusca", "version": "v1" }], "language": "PYTHON", "name": "google-mollusca" }, "snippets": [{ "clientMethod": { "method": { "service": { "shortName": "Squid" }, "shortName": "classify" } }, "segments": [{ "end": 28, "start": 2, "type": "FULL" }, { "end": 28, "start": 2, "type": "SHORT" }, { "end": 8, "start": 6, "type": "CLIENT_INITIALIZATION" }, { "end": 22, "start": 9, "type": "REQUEST_INITIALIZATION" }, { "end": 25, "start": 23, "type": "REQUEST_EXECUTION" }, { "end": 29, "start": 26, "type": "RESPONSE_HANDLING" }] }] }
def _fill_sample_metadata(sample: dict, api_schema: api.API): """Returns snippet metadata for the sample.""" # Snippet Metadata can't be fully filled out in any one function # In this function we add information from # the API schema and sample dictionary. # See `snippet_metadata.proto` for documentation on the fields service = api_schema.services[sample["service"]] method = service.methods[sample["rpc"]] async_ = sample["transport"] == api.TRANSPORT_GRPC_ASYNC snippet_metadata = snippet_metadata_pb2.Snippet() # type: ignore snippet_metadata.region_tag = sample["region_tag"] snippet_metadata.description = f"Sample for {sample['rpc']}" snippet_metadata.language = snippet_metadata_pb2.Language.PYTHON # type: ignore snippet_metadata.canonical = True snippet_metadata.origin = snippet_metadata_pb2.Snippet.Origin.API_DEFINITION # type: ignore # Service Client snippet_metadata.client_method.client.short_name = service.async_client_name if async_ else service.client_name snippet_metadata.client_method.client.full_name = f"{'.'.join(sample['module_namespace'])}.{sample['module_name']}.{snippet_metadata.client_method.client.short_name}" # Service snippet_metadata.client_method.method.service.short_name = service.name snippet_metadata.client_method.method.service.full_name = f"{api_schema.naming.proto_package}.{service.name}" # RPC snippet_metadata.client_method.method.short_name = method.name snippet_metadata.client_method.method.full_name = f"{api_schema.naming.proto_package}.{service.name}.{method.name}" # Client Method setattr(snippet_metadata.client_method, "async", async_) snippet_metadata.client_method.short_name = utils.to_snake_case( method.name) snippet_metadata.client_method.full_name = f"{snippet_metadata.client_method.client.full_name}.{snippet_metadata.client_method.short_name}" if not method.void: snippet_metadata.client_method.result_type = method.client_output_async.ident.sphinx if async_ else method.client_output.ident.sphinx if method.server_streaming: snippet_metadata.client_method.result_type = f"Iterable[{snippet_metadata.client_method.result_type }]" # Client Method Parameters parameters = snippet_metadata.client_method.parameters if not method.client_streaming: parameters.append( snippet_metadata_pb2.ClientMethod.Parameter( # type: ignore type=method.input.ident.sphinx, name="request")) for field in method.flattened_fields.values(): parameters.append( snippet_metadata_pb2.ClientMethod.Parameter( # type: ignore type=field.ident.sphinx, name=field.name)) else: parameters.append( snippet_metadata_pb2.ClientMethod.Parameter( # type: ignore type=f"Iterator[{method.input.ident.sphinx}]", name="requests")) parameters.append( snippet_metadata_pb2.ClientMethod.Parameter( # type: ignore name="retry", type="google.api_core.retry.Retry")) parameters.append( snippet_metadata_pb2.ClientMethod.Parameter( # type: ignore name="timeout", type="float")) parameters.append( snippet_metadata_pb2.ClientMethod.Parameter( # type: ignore name="metadata", type="Sequence[Tuple[str, str]")) return snippet_metadata
assert actual_response.file[1] == CodeGeneratorResponse.File( name="samples/generated_samples/clam_sample.py", content="\n", ) assert actual_response.file[ 2].name == "samples/generated_samples/snippet_metadata_mollusc_v1.json" assert json.loads( actual_response.file[2].content) == expected_snippet_index_json @mock.patch("gapic.samplegen.samplegen.generate_sample_specs", return_value=[]) @mock.patch( "gapic.samplegen.samplegen.generate_sample", return_value=("", snippet_metadata_pb2.Snippet()), ) def test_generate_autogen_samples(mock_generate_sample, mock_generate_specs): opts = Options.build("autogen-snippets") g = generator.Generator(opts) # Need to have the sample template visible to the generator. g._env.loader = jinja2.DictLoader({"sample.py.j2": ""}) api_schema = make_api( naming=naming.NewNaming(name="Mollusc", version="v6")) actual_response = g.get_response(api_schema, opts=opts) # Just check that generate_sample_specs was called # Correctness of the spec is tested in samplegen unit tests mock_generate_specs.assert_called_once_with(api_schema, opts=opts)