def test_address_name_builtin_keyword(): addr_builtin = metadata.Address( name="Any", module="any", package=("google", "protobuf"), api_naming=naming.NewNaming(proto_package="foo.bar.baz.v1"), ) assert addr_builtin.module_alias == "gp_any" addr_kword = metadata.Address( name="Class", module="class", package=("google", "protobuf"), api_naming=naming.NewNaming(proto_package="foo.bar.baz.v1"), ) assert addr_kword.module_alias == "gp_class"
def test_generator_duplicate_samples(fs): config_fpath = "samples.yaml" fs.create_file( config_fpath, contents=dedent(""" # Note: the samples are duplicates. type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid - id: squid_sample region_tag: humboldt_tag rpc: get_squid """), ) generator = make_generator("samples=samples.yaml") generator._env.loader = jinja2.DictLoader({"sample.py.j2": ""}) api_schema = make_api( naming=naming.NewNaming(name="Mollusc", version="v6")) with pytest.raises(types.DuplicateSample): generator.get_response(api_schema=api_schema, opts=Options.build(""))
def test_address_str_different_proto_package(): addr = metadata.Address( package=('google', 'iam', 'v1'), module='options', name='GetPolicyOptions', api_naming=naming.NewNaming(proto_package='foo.bar.baz.v1')) assert str(addr) == 'options_pb2.GetPolicyOptions'
def test_address_str_different_proto_package_with_collision(): addr = metadata.Address( package=('google', 'rpc'), module='status', name='Status', api_naming=naming.NewNaming(proto_package='foo.bar.baz.v1') ).with_context(collisions=frozenset({'status'})) # the module alias should be ignored for _pb2 types assert str(addr) == 'status_pb2.Status'
def test_message_pb2_sphinx_ident(): meta = metadata.Metadata( address=metadata.Address(name='Timestamp', package=('google', 'protobuf'), module='timestamp', api_naming=naming.NewNaming( proto_package="foo.bar"))) message = make_message("Timestamp", package='google.protobuf', module='timestamp', meta=meta) assert message.ident.sphinx == 'google.protobuf.timestamp_pb2.Timestamp'
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)
def test_samplegen_id_disambiguation(mock_gmtime, mock_generate_sample, fs): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner # Note: The first two samples will have the same nominal ID, the first by # explicit naming and the second by falling back to the region_tag. # The third has no id of any kind, so the generator is required to make a # unique ID for it. fs.create_file( "samples.yaml", contents=dedent(""" --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid_streaming # Note that this region tag collides with the id of the previous sample. - region_tag: squid_sample rpc: get_squid_streaming # No id or region tag. - rpc: get_squid_streaming """), ) g = generator.Generator(Options.build("samples=samples.yaml")) # 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=Options.build("")) expected_response = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/generated_samples/squid_sample_91a465c6.py", content="\n", ), CodeGeneratorResponse.File( name="samples/generated_samples/squid_sample_55051b38.py", content="\n", ), CodeGeneratorResponse.File( name="samples/generated_samples/157884ee.py", content="\n", ), # TODO(busunkim): Re-enable manifest generation once metadata # format has been formalized. # https://docs.google.com/document/d/1ghBam8vMj3xdoe4xfXhzVcOAIwrkbTpkMLgKc9RPD9k/edit#heading=h.sakzausv6hue # CodeGeneratorResponse.File( # name="samples/generated_samples/mollusc.v6.python.21120601.131313.manifest.yaml", # content=dedent( # """\ # --- # type: manifest/samples # schema_version: 3 # python: &python # environment: python # bin: python3 # base_path: samples # invocation: '{bin} {path} @args' # samples: # - <<: *python # sample: squid_sample_91a465c6 # path: '{base_path}/squid_sample_91a465c6.py' # region_tag: humboldt_tag # - <<: *python # sample: squid_sample_55051b38 # path: '{base_path}/squid_sample_55051b38.py' # region_tag: squid_sample # - <<: *python # sample: 157884ee # path: '{base_path}/157884ee.py' # """ # ), # ), ]) expected_response.supported_features |= ( CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL) assert actual_response == expected_response
def test_samplegen_config_to_output_files( mock_gmtime, mock_generate_sample, fs, ): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner fs.create_file( "samples.yaml", contents=dedent(""" --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid_streaming - region_tag: clam_sample rpc: get_clam """), ) g = generator.Generator(Options.build("samples=samples.yaml", )) # 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=Options.build("")) expected_response = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/generated_samples/squid_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/generated_samples/clam_sample.py", content="\n", ), # TODO(busunkim): Re-enable manifest generation once metadata # format has been formalized. # https://docs.google.com/document/d/1ghBam8vMj3xdoe4xfXhzVcOAIwrkbTpkMLgKc9RPD9k/edit#heading=h.sakzausv6hue # CodeGeneratorResponse.File( # name="samples/generated_samples/mollusc.v6.python.21120601.131313.manifest.yaml", # content=dedent( # """\ # --- # type: manifest/samples # schema_version: 3 # python: &python # environment: python # bin: python3 # base_path: samples # invocation: '{bin} {path} @args' # samples: # - <<: *python # sample: squid_sample # path: '{base_path}/squid_sample.py' # region_tag: humboldt_tag # - <<: *python # sample: clam_sample # path: '{base_path}/clam_sample.py' # region_tag: clam_sample # """ # ), # ), ]) expected_response.supported_features |= ( CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL) assert actual_response == expected_response
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_address_subpackage_empty(): addr = metadata.Address( package=('foo', 'bar', 'baz', 'v1'), api_naming=naming.NewNaming(proto_package='foo.bar.baz.v1'), ) assert addr.subpackage == ()
def test_address_subpackage_no_version(): addr = metadata.Address( package=('foo', 'bar', 'baz', 'spam', 'eggs'), api_naming=naming.NewNaming(proto_package='foo.bar.baz'), ) assert addr.subpackage == ('spam', 'eggs')
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' }
def test_dont_generate_in_code_samples(mock_gmtime, mock_generate_sample, fs): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner config_fpath = "samples.yaml" fs.create_file( config_fpath, contents=dedent(""" type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc sample_type: - standalone - incode/SQUID - id: clam_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc sample_type: - incode/CLAM - id: whelk_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc sample_type: - standalone - id: octopus_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc """), ) generator = make_generator(f"samples={config_fpath}") generator._env.loader = jinja2.DictLoader({"sample.py.j2": ""}) api_schema = make_api( make_proto( descriptor_pb2.FileDescriptorProto( name="mollusc.proto", package="Mollusc.v1", service=[ descriptor_pb2.ServiceDescriptorProto(name="Mollusc") ], ), ), naming=naming.NewNaming(name="Mollusc", version="v6"), ) # Note that we do NOT expect a clam sample. # There are four tests going on: # 1) Just an explicit standalone sample type. # 2) Multiple sample types, one of which is standalone. # 3) Explicit sample types but NO standalone sample type. # 4) Implicit standalone sample type. expected = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/generated_samples/squid_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/generated_samples/whelk_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/generated_samples/octopus_sample.py", content="\n", ), # TODO(busunkim): Re-enable manifest generation once metadata # format has been formalized. # https://docs.google.com/document/d/1ghBam8vMj3xdoe4xfXhzVcOAIwrkbTpkMLgKc9RPD9k/edit#heading=h.sakzausv6hue # CodeGeneratorResponse.File( # name="samples/generated_samples/mollusc.v6.python.21120601.131313.manifest.yaml", # content=dedent( # """ --- # type: manifest/samples # schema_version: 3 # python: &python # environment: python # bin: python3 # base_path: samples # invocation: \'{bin} {path} @args\' # samples: # - <<: *python # sample: squid_sample # path: \'{base_path}/squid_sample.py\' # - <<: *python # sample: whelk_sample # path: \'{base_path}/whelk_sample.py\' # - <<: *python # sample: octopus_sample # path: \'{base_path}/octopus_sample.py\' # """ # ), # ), ]) expected.supported_features |= CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL actual = generator.get_response(api_schema=api_schema, opts=Options.build("")) assert actual == expected
def test_samplegen_config_to_output_files( mock_gmtime, mock_generate_sample, fs, ): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner fs.create_file( "samples.yaml", contents=dedent(""" --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid_streaming - region_tag: clam_sample rpc: get_clam """), ) g = generator.Generator(Options.build("samples=samples.yaml", )) # 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=Options.build("")) expected_response = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/squid_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/clam_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/mollusc.v6.python.21120601.131313.manifest.yaml", content=dedent("""\ --- type: manifest/samples schema_version: 3 python: &python environment: python bin: python3 base_path: samples invocation: '{bin} {path} @args' samples: - <<: *python sample: squid_sample path: '{base_path}/squid_sample.py' region_tag: humboldt_tag - <<: *python sample: clam_sample path: '{base_path}/clam_sample.py' region_tag: clam_sample """), ), ]) expected_response.supported_features |= ( CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL) assert actual_response == expected_response
def make_naming(**kwargs) -> naming.Naming: kwargs.setdefault("name", "Hatstand") kwargs.setdefault("namespace", ("Google", "Cloud")) kwargs.setdefault("version", "v1") kwargs.setdefault("product_name", "Hatstand") return naming.NewNaming(**kwargs)
def test_samplegen_id_disambiguation(mock_gmtime, mock_generate_sample, fs): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner # Note: The first two samples will have the same nominal ID, the first by # explicit naming and the second by falling back to the region_tag. # The third has no id of any kind, so the generator is required to make a # unique ID for it. fs.create_file( "samples.yaml", contents=dedent(""" --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid_streaming # Note that this region tag collides with the id of the previous sample. - region_tag: squid_sample rpc: get_squid_streaming # No id or region tag. - rpc: get_squid_streaming """), ) g = generator.Generator(Options.build("samples=samples.yaml")) # 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=Options.build("")) expected_response = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/squid_sample_91a465c6.py", content="\n", ), CodeGeneratorResponse.File( name="samples/squid_sample_55051b38.py", content="\n", ), CodeGeneratorResponse.File( name="samples/157884ee.py", content="\n", ), CodeGeneratorResponse.File( name="samples/mollusc.v6.python.21120601.131313.manifest.yaml", content=dedent("""\ --- type: manifest/samples schema_version: 3 python: &python environment: python bin: python3 base_path: samples invocation: '{bin} {path} @args' samples: - <<: *python sample: squid_sample_91a465c6 path: '{base_path}/squid_sample_91a465c6.py' region_tag: humboldt_tag - <<: *python sample: squid_sample_55051b38 path: '{base_path}/squid_sample_55051b38.py' region_tag: squid_sample - <<: *python sample: 157884ee path: '{base_path}/157884ee.py' """), ), ]) expected_response.supported_features |= ( CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL) assert actual_response == expected_response
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 make_naming(**kwargs) -> naming.Naming: kwargs.setdefault('name', 'Hatstand') kwargs.setdefault('namespace', ('Google', 'Cloud')) kwargs.setdefault('version', 'v1') kwargs.setdefault('product_name', 'Hatstand') return naming.NewNaming(**kwargs)
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 test_dont_generate_in_code_samples(mock_gmtime, mock_generate_sample, fs): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner config_fpath = "samples.yaml" fs.create_file(config_fpath, contents=dedent(''' type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc sample_type: - standalone - incode/SQUID - id: clam_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc sample_type: - incode/CLAM - id: whelk_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc sample_type: - standalone - id: octopus_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc ''')) generator = make_generator(f'samples={config_fpath}') generator._env.loader = jinja2.DictLoader({'sample.py.j2': ''}) api_schema = make_api( make_proto( descriptor_pb2.FileDescriptorProto( name='mollusc.proto', package='Mollusc.v1', service=[ descriptor_pb2.ServiceDescriptorProto(name='Mollusc') ], ), ), naming=naming.NewNaming(name='Mollusc', version='v6'), ) # Note that we do NOT expect a clam sample. # There are four tests going on: # 1) Just an explicit standalone sample type. # 2) Multiple sample types, one of which is standalone. # 3) Explicit sample types but NO standalone sample type. # 4) Implicit standalone sample type. expected = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/squid_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/whelk_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/octopus_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/mollusc.v6.python.21120601.131313.manifest.yaml", content=dedent(""" --- type: manifest/samples schema_version: 3 python: &python environment: python bin: python3 base_path: samples invocation: \'{bin} {path} @args\' samples: - <<: *python sample: squid_sample path: \'{base_path}/squid_sample.py\' - <<: *python sample: whelk_sample path: \'{base_path}/whelk_sample.py\' - <<: *python sample: octopus_sample path: \'{base_path}/octopus_sample.py\' """)) ]) actual = generator.get_response(api_schema=api_schema, opts=options.Options.build('')) assert actual == expected