Skip to content

Commit

Permalink
feat(python_samples): Custom path for generation (#695)
Browse files Browse the repository at this point in the history
Added functionality to be used for generating documentation for Python samples. A demonstration of the documentation this code can render (Using the README.md template under [/python_samples/](https://github.com/googleapis/synthtool/tree/master/synthtool/gcp/templates/python_samples)) is available [here](https://github.com/runargs/python-docs-samples/tree/synth-DEMO/bigtable).

This function will default to generating the README in the current directory if the synth.py file is put in a sample folder, and or the "/samples" folder if it is placed in the top level of a client library repo. A custom path for where to generate may also be specified through the "sample_project_dir" key in .repo.metadata.json
  • Loading branch information
runargs authored Aug 3, 2020
1 parent bfcdbe0 commit 482d31d
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 2 deletions.
42 changes: 40 additions & 2 deletions synthtool/gcp/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from synthtool.log import logger
from synthtool.sources import git, templates


PathOrStr = templates.PathOrStr
TEMPLATES_URL: str = git.make_repo_clone_url("googleapis/synthtool")
DEFAULT_TEMPLATES_PATH = "synthtool/gcp/templates"
LOCAL_TEMPLATES: Optional[str] = os.environ.get("SYNTHTOOL_TEMPLATES")
Expand Down Expand Up @@ -63,10 +63,48 @@ def _generic_library(self, directory: str, **kwargs) -> Path:
return result

def py_samples(self, **kwargs) -> Path:
"""
Determines whether generation is being done in a client library or in a samples
folder so it can either generate in the current directory or the client lib's
'samples' folder. A custom path for where to generate may also be specified.
Renders README.md according to .repo-metadata.json
"""
# kwargs["metadata"] is required to load values from .repo-metadata.json
if "metadata" not in kwargs:
kwargs["metadata"] = {}
return self._generic_library("python_samples", **kwargs)
# load common repo meta information (metadata that's not language specific).
self._load_generic_metadata(kwargs["metadata"])
# temporary exclusion prior to old templates being migrated out
self.excludes.extend(
[
"README.rst",
"auth_api_key.tmpl.rst",
"auth.tmpl.rst",
"install_deps.tmpl.rst",
"install_portaudio.tmpl.rst",
"noxfile.py.j2",
]
)

in_client_library = Path("samples").exists()
sample_project_dir = kwargs["metadata"]["repo"].get("sample_project_dir")

if sample_project_dir is None: # Not found in metadata
if in_client_library:
sample_project_dir = "samples"
else:
sample_project_dir = "."
elif not Path(sample_project_dir).exists():
raise Exception(f"'{sample_project_dir}' does not exist")

logger.debug(
f"Generating templates for samples directory '{sample_project_dir}'"
)
py_samples_templates = Path(self._template_root) / "python_samples"
t = templates.TemplateGroup(py_samples_templates, self.excludes)
result = t.render(subdir=sample_project_dir, **kwargs)
_tracked_paths.add(result)
return result

def py_library(self, **kwargs) -> Path:
# kwargs["metadata"] is required to load values from .repo-metadata.json
Expand Down
24 changes: 24 additions & 0 deletions tests/generationmock/client_library/.repo-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "bigtable",
"name_pretty": "Cloud Bigtable",
"product_documentation": "https://cloud.google.com/bigtable",
"client_documentation": "https://googleapis.dev/python/bigtable/latest",
"issue_tracker": "https://issuetracker.google.com/savedsearches/559777",
"release_level": "ga",
"language": "python",
"repo": "googleapis/python-bigtable",
"distribution_name": "google-cloud-bigtable",
"api_id": "bigtable.googleapis.com",
"requires_billing": true,
"client_library": true,
"samples": [
{"name": "Quickstart",
"description": "Example sample for product",
"file": "quickstart.py",
"custom_content": "This is custom text for the sample",
"runnable": "True"},
{"name": "Hello World",
"description": "Example beginner application",
"file": "main.py"}
]
}
Empty file.
25 changes: 25 additions & 0 deletions tests/generationmock/custom_path/.repo-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "bigtable",
"name_pretty": "Cloud Bigtable",
"product_documentation": "https://cloud.google.com/bigtable",
"client_documentation": "https://googleapis.dev/python/bigtable/latest",
"issue_tracker": "https://issuetracker.google.com/savedsearches/559777",
"release_level": "ga",
"language": "python",
"repo": "googleapis/python-bigtable",
"distribution_name": "google-cloud-bigtable",
"api_id": "bigtable.googleapis.com",
"requires_billing": true,
"client_library": true,
"sample_project_dir": "custom_samples_folder",
"samples": [
{"name": "Quickstart",
"description": "Example sample for product",
"file": "quickstart.py",
"custom_content": "This is custom text for the sample",
"runnable": "True"},
{"name": "Hello World",
"description": "Example beginner application",
"file": "main.py"}
]
}
Empty file.
25 changes: 25 additions & 0 deletions tests/generationmock/custom_path_DNE/.repo-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "bigtable",
"name_pretty": "Cloud Bigtable",
"product_documentation": "https://cloud.google.com/bigtable",
"client_documentation": "https://googleapis.dev/python/bigtable/latest",
"issue_tracker": "https://issuetracker.google.com/savedsearches/559777",
"release_level": "ga",
"language": "python",
"repo": "googleapis/python-bigtable",
"distribution_name": "google-cloud-bigtable",
"api_id": "bigtable.googleapis.com",
"requires_billing": true,
"client_library": true,
"sample_project_dir": "nonexistent_folder",
"samples": [
{"name": "Quickstart",
"description": "Example sample for product",
"file": "quickstart.py",
"custom_content": "This is custom text for the sample",
"runnable": "True"},
{"name": "Hello World",
"description": "Example beginner application",
"file": "main.py"}
]
}
24 changes: 24 additions & 0 deletions tests/generationmock/samples_folder/.repo-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "bigtable",
"name_pretty": "Cloud Bigtable",
"product_documentation": "https://cloud.google.com/bigtable",
"client_documentation": "https://googleapis.dev/python/bigtable/latest",
"issue_tracker": "https://issuetracker.google.com/savedsearches/559777",
"release_level": "ga",
"language": "python",
"repo": "googleapis/python-bigtable",
"distribution_name": "google-cloud-bigtable",
"api_id": "bigtable.googleapis.com",
"requires_billing": true,
"client_library": true,
"samples": [
{"name": "Quickstart",
"description": "Example sample for product",
"file": "quickstart.py",
"custom_content": "This is custom text for the sample",
"runnable": "True"},
{"name": "Hello World",
"description": "Example beginner application",
"file": "main.py"}
]
}
80 changes: 80 additions & 0 deletions tests/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
# limitations under the License.

from synthtool.gcp.common import decamelize
from pathlib import Path
from pytest import raises
import os
import synthtool as s
import tempfile
import shutil

MOCK = Path(__file__).parent / "generationmock"
common = s.gcp.CommonTemplates()


def test_converts_camel_to_title():
Expand All @@ -29,3 +38,74 @@ def test_handles_acronym():
def test_handles_empty_string():
assert decamelize(None) == ""
assert decamelize("") == ""


def test_py_samples_clientlib():
path_to_gen = MOCK / "client_library"
with tempfile.TemporaryDirectory() as tempdir:
workdir = shutil.copytree(path_to_gen, Path(tempdir) / "client_library")
cwd = os.getcwd()
os.chdir(workdir)

try:
sample_files = common.py_samples(
unit_cov_level=97, cov_level=99, samples=True
)
s.move(sample_files, excludes=["noxfile.py"])
assert os.path.isfile(workdir / "samples" / "README.md")
finally:
os.chdir(cwd)


def test_py_samples_custom_path():
path_to_gen = MOCK / "custom_path"
with tempfile.TemporaryDirectory() as tempdir:
workdir = shutil.copytree(path_to_gen, Path(tempdir) / "custom_path")
cwd = os.getcwd()
os.chdir(workdir)

try:
sample_files = common.py_samples(
unit_cov_level=97, cov_level=99, samples=True
)
s.move(sample_files, excludes=["noxfile.py"])
assert os.path.isfile(workdir / "custom_samples_folder" / "README.md")
finally:
os.chdir(cwd)


def test_py_samples_custom_path_DNE():
with tempfile.TemporaryDirectory() as tempdir:
workdir = shutil.copytree(
MOCK / "custom_path_DNE", Path(tempdir) / "custom_path_DNE"
)
cwd = os.getcwd()
os.chdir(workdir)

try:
with raises(Exception) as e:
os.chdir(workdir / "custom_path_DNE")
sample_files = common.py_samples(
unit_cov_level=97, cov_level=99, samples=True
)
s.move(sample_files, excludes=["noxfile.py"])
assert "'nonexistent_folder' does not exist" in str(e.value)
finally:
os.chdir(cwd)


def test_py_samples_samples_folder():
path_to_gen = MOCK / "samples_folder"
with tempfile.TemporaryDirectory() as tempdir:
workdir = shutil.copytree(path_to_gen, Path(tempdir) / "samples_folder")
cwd = os.getcwd()
os.chdir(workdir)

try:
sample_files = common.py_samples(
unit_cov_level=97, cov_level=99, samples=True
)
s.move(sample_files, excludes=["noxfile.py"])
assert os.path.isfile(workdir / "README.md")
finally:
os.chdir(cwd)
3 changes: 3 additions & 0 deletions tests/test_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ def tearDown(self):
return super().tearDown()

def testClone(self):
# clear out metadata before creating new metadata and asserting on it
metadata.reset()

local_directory = git.clone("https://github.com/googleapis/nodejs-vision.git")
self.assertEqual("nodejs-vision", local_directory.name)
self.assertEqual("nodejs-vision", metadata.get().sources[0].git.name)
Expand Down

0 comments on commit 482d31d

Please # to comment.