2020import re
2121import time
2222
23- from gapic .samplegen_utils import ( types , yaml )
23+ from gapic .samplegen_utils import types
2424from gapic .schema import (api , wrappers )
2525
2626from collections import (defaultdict , namedtuple , ChainMap as chainmap )
5555 )
5656)
5757
58- # TODO: configure the base template name so that
59- # e.g. other languages can use the same machinery.
60- TEMPLATE_NAME = "sample.py.j2"
58+ DEFAULT_TEMPLATE_NAME = "sample.py.j2"
6159
6260
6361@dataclasses .dataclass (frozen = True )
@@ -106,20 +104,6 @@ class TransformedRequest:
106104 body : Optional [List [AttributeRequestSetup ]]
107105
108106
109- def coerce_response_name (s : str ) -> str :
110- # In the sample config, the "$resp" keyword is used to refer to the
111- # item of interest as received by the corresponding calling form.
112- # For a 'regular', i.e. unary, synchronous, non-long-running method,
113- # it's the return value; for a server-streaming method, it's the iteration
114- # variable in the for loop that iterates over the return value, and for
115- # a long running promise, the user calls result on the method return value to
116- # resolve the future.
117- #
118- # The sample schema uses '$resp' as the special variable,
119- # but in the samples the 'response' variable is used instead.
120- return s .replace ("$resp" , "response" )
121-
122-
123107class Validator :
124108 """Class that validates a sample.
125109
@@ -160,6 +144,17 @@ def __init__(self, method: wrappers.Method):
160144 }
161145 )
162146
147+ @staticmethod
148+ def preprocess_sample (sample , api_schema ):
149+ """Modify a sample to set default or missing fields.
150+
151+ Args:
152+ sample (Any): A definition for a single sample generated from parsed yaml.
153+ api_schema (api.API): The schema that defines the API to which the sample belongs.
154+ """
155+ sample ["package_name" ] = api_schema .naming .warehouse_package_name
156+ sample .setdefault ("response" , [{"print" : ["%s" , "$resp" ]}])
157+
163158 def var_field (self , var_name : str ) -> Optional [wrappers .Field ]:
164159 return self .var_defs_ .get (var_name )
165160
@@ -661,7 +656,8 @@ def _validate_loop(self, loop):
661656
662657def generate_sample (sample ,
663658 env : jinja2 .environment .Environment ,
664- api_schema : api .API ) -> str :
659+ api_schema : api .API ,
660+ template_name : str = DEFAULT_TEMPLATE_NAME ) -> str :
665661 """Generate a standalone, runnable sample.
666662
667663 Rendering and writing the rendered output is left for the caller.
@@ -671,11 +667,13 @@ def generate_sample(sample,
671667 env (jinja2.environment.Environment): The jinja environment used to generate
672668 the filled template for the sample.
673669 api_schema (api.API): The schema that defines the API to which the sample belongs.
670+ template_name (str): An optional override for the name of the template
671+ used to generate the sample.
674672
675673 Returns:
676674 str: The rendered sample.
677675 """
678- sample_template = env .get_template (TEMPLATE_NAME )
676+ sample_template = env .get_template (template_name )
679677
680678 service_name = sample ["service" ]
681679 service = api_schema .services .get (service_name )
@@ -693,99 +691,17 @@ def generate_sample(sample,
693691 calling_form = types .CallingForm .method_default (rpc )
694692
695693 v = Validator (rpc )
694+ # Tweak some small aspects of the sample to set sane defaults for optional
695+ # fields, add fields that are required for the template, and so forth.
696+ v .preprocess_sample (sample , api_schema )
696697 sample ["request" ] = v .validate_and_transform_request (calling_form ,
697698 sample ["request" ])
698699 v .validate_response (sample ["response" ])
699700
700- sample ["package_name" ] = api_schema .naming .warehouse_package_name
701-
702701 return sample_template .render (
703702 file_header = FILE_HEADER ,
704703 sample = sample ,
705704 imports = [],
706705 calling_form = calling_form ,
707706 calling_form_enum = types .CallingForm ,
708707 )
709-
710-
711- def generate_manifest (
712- fpaths_and_samples ,
713- base_path : str ,
714- api_schema ,
715- * ,
716- manifest_time : int = None
717- ) -> Tuple [str , yaml .Doc ]:
718- """Generate a samplegen manifest for use by sampletest
719-
720- Args:
721- fpaths_and_samples (Iterable[Tuple[str, Mapping[str, Any]]]):
722- The file paths and samples to be listed in the manifest
723- base_path (str): The base directory where the samples are generated.
724- api_schema (~.api.API): An API schema object.
725- manifest_time (int): Optional. An override for the timestamp in the name of the manifest filename.
726- Primarily used for testing.
727-
728- Returns:
729- Tuple[str, yaml.Doc]: The filename of the manifest and the manifest data as a dictionary.
730-
731- """
732-
733- doc = yaml .Doc (
734- [
735- yaml .KeyVal ("type" , "manifest/samples" ),
736- yaml .KeyVal ("schema_version" , "3" ),
737- # TODO: make the environment configurable to allow other languages
738- # to use the same basic machinery.
739- yaml .Map (
740- name = "python" ,
741- anchor_name = "python" ,
742- elements = [
743- yaml .KeyVal ("environment" , "python" ),
744- yaml .KeyVal ("bin" , "python3" ),
745- yaml .KeyVal ("base_path" , base_path ),
746- yaml .KeyVal ("invocation" , "'{bin} {path} @args'" ),
747- ],
748- ),
749- yaml .Collection (
750- name = "samples" ,
751- elements = [
752- [ # type: ignore
753- # Mypy doesn't correctly intuit the type of the
754- # "region_tag" conditional expression.
755- yaml .Alias ("python" ),
756- yaml .KeyVal ("sample" , sample ["id" ]),
757- yaml .KeyVal ("path" ,
758- "'{base_path}/%s'" % os .path .relpath (fpath ,
759- base_path )),
760- (yaml .KeyVal ("region_tag" , sample ["region_tag" ])
761- if "region_tag" in sample else
762- yaml .Null ),
763-
764- ]
765- for fpath , sample in fpaths_and_samples
766- ],
767- ),
768- ]
769- )
770-
771- dt = time .gmtime (manifest_time )
772- # TODO: allow other language configuration
773- manifest_fname_template = (
774- "{api}.{version}.python."
775- "{year:04d}{month:02d}{day:02d}."
776- "{hour:02d}{minute:02d}{second:02d}."
777- "manifest.yaml"
778- )
779-
780- manifest_fname = manifest_fname_template .format (
781- api = api_schema .naming .name ,
782- version = api_schema .naming .version ,
783- year = dt .tm_year ,
784- month = dt .tm_mon ,
785- day = dt .tm_mday ,
786- hour = dt .tm_hour ,
787- minute = dt .tm_min ,
788- second = dt .tm_sec ,
789- )
790-
791- return manifest_fname , doc
0 commit comments