Skip to content

Commit 3b38b45

Browse files
authored
chore: configured snippet generates empty sample function (#1525)
* chore: configured snippet generates empty sample function
1 parent 4ebe096 commit 3b38b45

File tree

5 files changed

+128
-25
lines changed

5 files changed

+128
-25
lines changed

packages/gapic-generator/gapic/configurable_snippetgen/configured_snippet.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,23 @@
1717
import inflection
1818
import libcst
1919

20+
from gapic.configurable_snippetgen import libcst_utils
2021
from gapic.configurable_snippetgen import snippet_config_language_pb2
2122
from gapic.schema import api
2223

2324

24-
def _make_empty_module() -> libcst.Module:
25-
return libcst.Module(body=[])
26-
27-
28-
@dataclasses.dataclass(frozen=True)
25+
@dataclasses.dataclass
2926
class ConfiguredSnippet:
3027
api_schema: api.API
3128
config: snippet_config_language_pb2.SnippetConfig
3229
api_version: str
3330
is_sync: bool
34-
_module: libcst.Module = dataclasses.field(
35-
default_factory=_make_empty_module, init=False
36-
)
31+
32+
def __post_init__(self):
33+
self._module: libcst.Module = libcst_utils.empty_module()
34+
self._sample_function_def: libcst.FunctionDef = libcst_utils.base_function_def(
35+
function_name=self.sample_function_name, is_sync=self.is_sync
36+
)
3737

3838
@property
3939
def code(self) -> str:
@@ -78,3 +78,26 @@ def filename(self) -> str:
7878
config_id = self.config.metadata.config_id
7979
sync_or_async = "sync" if self.is_sync else "async"
8080
return f"{module_name}_{self.api_version}_generated_{service_name}_{snake_case_rpc_name}_{config_id}_{sync_or_async}.py"
81+
82+
def _build_sample_function(self) -> None:
83+
# TODO: https://github.com/googleapis/gapic-generator-python/issues/1536, add return type.
84+
# TODO: https://github.com/googleapis/gapic-generator-python/issues/1537, add sample function parameters.
85+
# TODO: https://github.com/googleapis/gapic-generator-python/issues/1538, add docstring.
86+
# TODO: https://github.com/googleapis/gapic-generator-python/issues/1539, add sample function body.
87+
pass
88+
89+
def _add_sample_function(self) -> None:
90+
self._module = self._module.with_changes(
91+
body=[self._sample_function_def])
92+
93+
def generate(self) -> None:
94+
"""Generates the snippet.
95+
96+
This is the main entrypoint of a ConfiguredSnippet instance, calling
97+
other methods to update self._module.
98+
"""
99+
self._build_sample_function()
100+
self._add_sample_function()
101+
# TODO: https://github.com/googleapis/gapic-generator-python/issues/1535, add imports.
102+
# TODO: https://github.com/googleapis/gapic-generator-python/issues/1534, add region tag.
103+
# TODO: https://github.com/googleapis/gapic-generator-python/issues/1533, add header.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import libcst
16+
17+
from gapic.configurable_snippetgen import snippet_config_language_pb2
18+
19+
20+
def empty_module() -> libcst.Module:
21+
return libcst.Module(body=[])
22+
23+
24+
def base_function_def(function_name: str, is_sync: bool) -> libcst.FunctionDef:
25+
"""Returns a FunctionDef node with a placeholder docstring."""
26+
params = libcst.Parameters(params=[])
27+
body = libcst.IndentedBlock(body=[libcst.parse_statement('""')])
28+
asynchronous = None if is_sync else libcst.Asynchronous()
29+
function_def = libcst.FunctionDef(
30+
name=libcst.Name(value=function_name),
31+
params=params,
32+
body=body,
33+
asynchronous=asynchronous,
34+
)
35+
36+
return function_def

packages/gapic-generator/tests/unit/configurable_snippetgen/test_configured_snippet.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,11 @@
2626

2727

2828
CURRENT_DIRECTORY = Path(__file__).parent.absolute()
29-
SPEECH_V1_REQUEST_PATH = (CURRENT_DIRECTORY /
30-
"resources" / "speech" / "request.desc")
29+
SPEECH_V1_REQUEST_PATH = CURRENT_DIRECTORY / \
30+
"resources" / "speech" / "request.desc"
3131
CONFIG_JSON_PATH = (
32-
CURRENT_DIRECTORY /
33-
"resources" /
34-
"speech" /
35-
"speech_createCustomClass.json")
32+
CURRENT_DIRECTORY / "resources" / "speech" / "speech_createCustomClass.json"
33+
)
3634

3735

3836
def _load_api_schema(request_path: Path) -> api.API:
@@ -79,16 +77,13 @@ def _make_configured_snippet(
7977
@pytest.fixture
8078
def snippet():
8179
return _make_configured_snippet(
82-
SPEECH_V1_REQUEST_PATH,
83-
CONFIG_JSON_PATH,
84-
api_version="v1",
85-
is_sync=True)
80+
SPEECH_V1_REQUEST_PATH, CONFIG_JSON_PATH, api_version="v1", is_sync=True
81+
)
8682

8783

8884
def test_region_tag(snippet):
8985
assert (
90-
snippet.region_tag
91-
== "speech_v1_config_Adaptation_CreateCustomClass_Basic_sync"
86+
snippet.region_tag == "speech_v1_config_Adaptation_CreateCustomClass_Basic_sync"
9287
)
9388

9489

@@ -97,13 +92,19 @@ def test_sample_function_name(snippet):
9792

9893

9994
def test_filename(snippet):
100-
assert snippet.filename == "speech_v1_generated_Adaptation_create_custom_class_Basic_sync.py"
95+
assert (
96+
snippet.filename
97+
== "speech_v1_generated_Adaptation_create_custom_class_Basic_sync.py"
98+
)
10199

102100

103101
def test_code(snippet):
102+
snippet.generate()
103+
104104
# https://github.com/googleapis/gapic-generator-python/issues/1522
105105
# Placeholder code. We will gradually add to the ConfiguredSnippet class
106106
# until the generated code is the same as that of the golden file.
107-
expected_code = "\n"
108-
107+
expected_code = """def sample_create_custom_class_Basic():
108+
\"\"
109+
"""
109110
assert snippet.code == expected_code
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2022 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
import libcst
17+
import pytest
18+
19+
from gapic.configurable_snippetgen import libcst_utils
20+
21+
22+
def _assert_code_equal(node: libcst.CSTNode, code: str) -> str:
23+
assert libcst.Module(body=[node]).code == code
24+
25+
26+
@pytest.mark.parametrize(
27+
"is_sync,expected_code",
28+
[
29+
(True, 'def some_function():\n ""\n'),
30+
(False, 'async def some_function():\n ""\n'),
31+
],
32+
)
33+
def test_base_function_def(is_sync, expected_code):
34+
node = libcst_utils.base_function_def("some_function", is_sync)
35+
36+
expected_node = libcst.parse_statement(expected_code)
37+
38+
# Whenever possible we try to control the shape of the nodes,
39+
# because we will be manipulating them during snippet generation.
40+
assert node.deep_equals(expected_node), (node, expected_node)
41+
42+
# Sometimes it is more convenient to just verify the code.
43+
_assert_code_equal(node, expected_code)

packages/gapic-generator/tests/unit/configurable_snippetgen/test_resources.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323

2424

2525
CURRENT_DIRECTORY = Path(__file__).parent.absolute()
26-
SPEECH_V1_REQUEST_PATH = (CURRENT_DIRECTORY /
27-
"resources" / "speech" / "request.desc")
26+
SPEECH_V1_REQUEST_PATH = CURRENT_DIRECTORY / \
27+
"resources" / "speech" / "request.desc"
2828

2929

3030
def test_request():

0 commit comments

Comments
 (0)