def test_generate_sample_config_partial_config(fs): expected_path = 'sample.yaml' fs.create_file( expected_path, # Note the typo: SampleConfigPronto contents=dedent( ''' --- type: com.google.api.codegen.SampleConfigPronto schema_version: 1.2.0 samples: - service: google.cloud.language.v1.LanguageService --- # Note: this one IS a valid config type: com.google.api.codegen.SampleConfigProto schema_version: 1.2.0 samples: - service: google.cloud.language.v1.LanguageService ''' ) ) expected_paths = [expected_path] actual_paths = list(gapic_utils.generate_all_sample_fpaths(expected_path)) assert actual_paths == expected_paths
def test_generate_sample_config_fpaths(fs): expected_path = 'cfgs/sample_config.yaml' fs.create_file(expected_path, contents=dedent(''' --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - service: google.cloud.language.v1.LanguageService ''')) actual_paths = list(gapic_utils.generate_all_sample_fpaths(expected_path)) assert actual_paths == [expected_path]
def test_generate_sample_config_fpaths_bad_contents( fs, # Note the typo: SampleConfigPronto contents=dedent(''' --- type: com.google.api.codegen.SampleConfigPronto schema_version: 1.2.0 samples: - service: google.cloud.language.v1.LanguageService ''')): expected_path = 'cfgs/sample_config.yaml' fs.create_file(expected_path, contents=contents) with pytest.raises(types.InvalidConfig): list(gapic_utils.generate_all_sample_fpaths(expected_path))
def build(cls, opt_string: str) -> 'Options': """Build an Options instance based on a protoc opt string. Args: opt_string (str): A string, as passed from the protoc interface (through ``--python_gapic_opt``). If multiple options are passed, then protoc joins the values with ``,``. By convention, we use ``key=value`` strings for such options, with an absent value defaulting to ``True``. Returns: ~.Options: The Options instance. Raises: gapic.samplegen_utils.types.InvalidConfig: If paths to files or directories that should contain sample configs are passed and no valid sample config is found. """ # Parse out every option beginning with `python-gapic` opts: DefaultDict[str, List[str]] = defaultdict(list) for opt in opt_string.split(','): # Parse out the key and value. value = 'true' if '=' in opt: opt, value = opt.split('=') if opt == cls.SAMPLES_OPT: opts[cls.SAMPLES_OPT].append(value) # Throw away other options not meant for us. if not opt.startswith(cls.PYTHON_GAPIC_PREFIX): continue # Set the option, using a key with the "python-gapic-" prefix # stripped. # # Just assume everything is a list at this point, and the # final instantiation step can de-list-ify where appropriate. opts[opt[len(cls.PYTHON_GAPIC_PREFIX):]].append(value) # If templates are specified, one of the specified directories # may be our default; perform that replacement. templates = opts.pop('templates', ['DEFAULT']) while 'DEFAULT' in templates: templates[templates.index('DEFAULT')] = os.path.realpath( os.path.join(os.path.dirname(__file__), '..', 'templates'), ) # Build the options instance. sample_paths = opts.pop(cls.SAMPLES_OPT, []) answer = Options( name=opts.pop('name', ['']).pop(), namespace=tuple(opts.pop('namespace', [])), templates=tuple(os.path.expanduser(i) for i in templates), sample_configs=tuple( cfg_path for s in sample_paths for cfg_path in samplegen_utils.generate_all_sample_fpaths(s)), ) # Note: if we ever need to recursively check directories for sample configs, # check that at least _one_ config is read in. # If there are any options remaining, then we failed to recognize # them -- complain. for key in opts.keys(): warnings.warn(f'Unrecognized option: `python-gapic-{key}`.') # Done; return the built options. return answer
def build(cls, opt_string: str) -> 'Options': """Build an Options instance based on a protoc opt string. Args: opt_string (str): A string, as passed from the protoc interface (through ``--python_gapic_opt``). If multiple options are passed, then protoc joins the values with ``,``. By convention, we use ``key=value`` strings for such options, with an absent value defaulting to ``True``. Returns: ~.Options: The Options instance. Raises: gapic.samplegen_utils.types.InvalidConfig: If paths to files or directories that should contain sample configs are passed and no valid sample config is found. """ # Parse out every option beginning with `python-gapic` opts: DefaultDict[str, List[str]] = defaultdict(list) for opt in opt_string.split(','): opt = opt.strip() # Parse out the key and value. value = 'true' if '=' in opt: opt, value = opt.split('=') # Save known, expected keys. if opt in cls.OPT_FLAGS: opts[opt].append(value) # Throw away other options not meant for us. if not opt.startswith(cls.PYTHON_GAPIC_PREFIX): continue # Set the option, using a key with the "python-gapic-" prefix # stripped. # # Just assume everything is a list at this point, and the # final instantiation step can de-list-ify where appropriate. opts[opt[len(cls.PYTHON_GAPIC_PREFIX):]].append(value) # If templates are specified, one of the specified directories # may be our default; perform that replacement. default_token = 'DEFAULT' templates = opts.pop('templates', [default_token]) pwd = path.join(path.dirname(__file__), '..') default_path = path.realpath(path.join(pwd, 'templates')) def tweak_path(p): if p == default_token: return default_path if path.isabs(p): return path.normpath(p) return path.normpath(path.join(pwd, p)) templates = [tweak_path(p) for p in templates] retry_cfg = None retry_paths = opts.pop('retry-config', None) if retry_paths: # Just use the last config specified. with open(retry_paths[-1]) as f: retry_cfg = json.load(f) # Build the options instance. sample_paths = opts.pop('samples', []) answer = Options( name=opts.pop('name', ['']).pop(), namespace=tuple(opts.pop('namespace', [])), retry=retry_cfg, sample_configs=tuple( cfg_path for s in sample_paths for cfg_path in samplegen_utils.generate_all_sample_fpaths(s)), templates=tuple(path.expanduser(i) for i in templates), lazy_import=bool(opts.pop('lazy-import', False)), old_naming=bool(opts.pop('old-naming', False)), ) # Note: if we ever need to recursively check directories for sample # configs, check that at least _one_ config is read in. # If there are any options remaining, then we failed to recognize # them -- complain. for key in opts.keys(): warnings.warn(f'Unrecognized option: `python-gapic-{key}`.') # Done; return the built options. return answer
def test_generate_sample_config_fpaths_no_such_file(fs): with pytest.raises(types.InvalidConfig): list(gapic_utils.generate_all_sample_fpaths('cfgs/sample_config.yaml'))
def test_generate_sample_config_fpaths_not_yaml(fs): expected_path = 'cfgs/sample_config.not_yaml' fs.create_file(expected_path) with pytest.raises(types.InvalidConfig): list(gapic_utils.generate_all_sample_fpaths(expected_path))
def build(cls, opt_string: str) -> 'Options': """Build an Options instance based on a protoc opt string. Args: opt_string (str): A string, as passed from the protoc interface (through ``--python_gapic_opt``). If multiple options are passed, then protoc joins the values with ``,``. By convention, we use ``key=value`` strings for such options, with an absent value defaulting to ``True``. Returns: ~.Options: The Options instance. Raises: gapic.samplegen_utils.types.InvalidConfig: If paths to files or directories that should contain sample configs are passed and no valid sample config is found. """ # Parse out every option beginning with `python-gapic` opts: DefaultDict[str, List[str]] = defaultdict(list) for opt in opt_string.split(','): opt = opt.strip() # Parse out the key and value. value = 'true' if '=' in opt: opt, value = opt.split('=') # Save known, expected keys. if opt in cls.OPT_FLAGS: opts[opt].append(value) # Throw away other options not meant for us. if not opt.startswith(cls.PYTHON_GAPIC_PREFIX): continue # Set the option, using a key with the "python-gapic-" prefix # stripped. # # Just assume everything is a list at this point, and the # final instantiation step can de-list-ify where appropriate. opts[opt[len(cls.PYTHON_GAPIC_PREFIX):]].append(value) # If templates are specified, one of the specified directories # may be our default; perform that replacement. default_token = 'DEFAULT' templates = opts.pop('templates', [default_token]) pwd = path.join(path.dirname(__file__), '..') default_path = path.realpath(path.join(pwd, 'templates')) def tweak_path(p): if p == default_token: return default_path if path.isabs(p): return path.normpath(p) return path.normpath(path.join(pwd, p)) templates = [tweak_path(p) for p in templates] retry_cfg = None retry_paths = opts.pop('retry-config', None) if retry_paths: # Just use the last config specified. with open(retry_paths[-1]) as f: retry_cfg = json.load(f) service_yaml_config = {} service_yaml_paths = opts.pop('service-yaml', None) if service_yaml_paths: # Just use the last file specified. with open(service_yaml_paths[-1]) as f: service_yaml_config = yaml.load(f, Loader=yaml.Loader) # The yaml service files typically have this field, # but it is not a field in the gogle.api.Service proto. service_yaml_config.pop('type', None) # Build the options instance. sample_paths = opts.pop('samples', []) # autogen-snippets is True by default, so make sure users can disable # by passing `autogen-snippets=false` autogen_snippets = opts.pop("autogen-snippets", ["True"])[0] in ("True", "true", "T", "t", "TRUE") # NOTE: Snippets are not currently correct for the alternative (Ads) templates # so always disable snippetgen in that case # https://github.com/googleapis/gapic-generator-python/issues/1052 old_naming = bool(opts.pop('old-naming', False)) if old_naming: autogen_snippets = False answer = Options( name=opts.pop('name', ['']).pop(), namespace=tuple(opts.pop('namespace', [])), warehouse_package_name=opts.pop('warehouse-package-name', ['']).pop(), retry=retry_cfg, sample_configs=tuple( cfg_path for s in sample_paths for cfg_path in samplegen_utils.generate_all_sample_fpaths(s)), autogen_snippets=autogen_snippets, templates=tuple(path.expanduser(i) for i in templates), lazy_import=bool(opts.pop('lazy-import', False)), old_naming=old_naming, add_iam_methods=bool(opts.pop('add-iam-methods', False)), metadata=bool(opts.pop('metadata', False)), # transport should include desired transports delimited by '+', e.g. transport='grpc+rest' transport=opts.pop('transport', ['grpc'])[0].split('+'), service_yaml_config=service_yaml_config, ) # Note: if we ever need to recursively check directories for sample # configs, check that at least _one_ config is read in. # If there are any options remaining, then we failed to recognize # them -- complain. for key in opts.keys(): warnings.warn(f'Unrecognized option: `python-gapic-{key}`.') # Done; return the built options. return answer