tools/azure-rest-api-specs-examples-automation/python/main.py (170 lines of code) (raw):
import sys
import urllib.parse
import os
from os import path
import glob
import json
import argparse
import logging
import dataclasses
from typing import List, Optional
import importlib.util
spec_location = (
"./directory/examples_dir.py" if path.exists("./directory/examples_dir.py") else "../directory/examples_dir.py"
)
spec = importlib.util.spec_from_file_location("examples_dir", spec_location)
examples_dir = importlib.util.module_from_spec(spec)
spec.loader.exec_module(examples_dir)
script_path: str = "."
tmp_path: str
specs_path: str
sdk_package_path: str
original_file_key: str = "# x-ms-original-file: "
module_relative_path: str = ""
@dataclasses.dataclass(eq=True, frozen=True)
class Release:
tag: str
package: str
version: str
@dataclasses.dataclass(eq=True)
class PythonExample:
target_filename: str
target_dir: str
content: str
def parse_python_example(lines: List[str]) -> Optional[PythonExample]:
# check metadata to see if the sample file is a candidate for example extraction
example_relative_path = None
for line in lines:
if line.strip().startswith(original_file_key):
example_relative_path = line.strip()[len(original_file_key) :]
break
example = None
if example_relative_path:
example_dir, example_filename = path.split(example_relative_path)
try:
example_dir = examples_dir.try_find_resource_manager_example(
specs_path, sdk_package_path, example_dir, example_filename
)
except NameError:
pass
target_dir = (
(example_dir + "-python")
if example_dir.endswith("/examples")
else example_dir.replace("/examples/", "/examples-python/")
)
filename = example_filename.split(".")[0]
first_line_index = 0
for index, line in enumerate(lines):
if line.strip() and not line.strip().startswith("# "):
first_line_index = index
break
lines = lines[first_line_index:]
example = PythonExample(filename, target_dir, "".join(lines))
return example
def process_python_example(filepath: str) -> List[PythonExample]:
# process aggregated Python sample to examples
filename = path.basename(filepath)
logging.info(f"Processing Python sample: {filename}")
with open(filepath, encoding="utf-8") as f:
lines = f.readlines()
python_examples = []
python_example = parse_python_example(lines)
if python_example:
python_examples.append(python_example)
return python_examples
def generate_examples(release: Release, sdk_examples_path: str, python_examples: List[PythonExample]) -> List[str]:
# generate code and metadata from Python examples
global module_relative_path
files = []
for python_example in python_examples:
escaped_release_tag = urllib.parse.quote(release.tag, safe="")
doc_link = (
f"https://github.com/Azure/azure-sdk-for-python/blob/{escaped_release_tag}/"
f"{module_relative_path}/README.md"
)
files.extend(
write_code_to_file(
sdk_examples_path,
python_example.target_dir,
python_example.target_filename,
".py",
python_example.content,
doc_link,
)
)
return files
def write_code_to_file(
sdk_examples_path: str, target_dir: str, filename_root: str, filename_ext: str, code_content: str, sdk_url: str
) -> List[str]:
# write code file and metadata file
code_filename = filename_root + filename_ext
metadata_filename = filename_root + ".json"
metadata_json = {"sdkUrl": sdk_url}
target_dir_path = path.join(sdk_examples_path, target_dir)
os.makedirs(target_dir_path, exist_ok=True)
code_file_path = path.join(target_dir_path, code_filename)
with open(code_file_path, "w", encoding="utf-8") as f:
f.write(code_content)
logging.info(f"Code written to file: {code_file_path}")
metadata_file_path = path.join(target_dir_path, metadata_filename)
with open(metadata_file_path, "w", encoding="utf-8") as f:
json.dump(metadata_json, f)
logging.info(f"Metadata written to file: {metadata_file_path}")
return [path.join(target_dir, code_filename), path.join(target_dir, metadata_filename)]
def create_python_examples(
release: Release, js_module: str, sdk_examples_path: str, js_examples_path: str
) -> (bool, List[str]):
python_paths = []
for root, dirs, files in os.walk(js_examples_path):
for name in files:
filepath = path.join(root, name)
if path.splitext(filepath)[1] == ".py":
python_paths.append(filepath)
logging.info(f"Processing SDK examples: {release.package}")
python_examples = []
for filepath in python_paths:
python_examples += process_python_example(filepath)
files = []
if python_examples:
logging.info("Writing SDK examples")
files = generate_examples(release, sdk_examples_path, python_examples)
return True, files
else:
logging.info("SDK examples not found")
return True, files
def get_module_relative_path(sdk_name: str, sdk_path: str) -> str:
global module_relative_path
candidate_sdk_paths = glob.glob(path.join(sdk_path, f"sdk/*/{sdk_name}"))
if len(candidate_sdk_paths) > 0:
candidate_sdk_paths = [path.relpath(p, sdk_path) for p in candidate_sdk_paths]
logging.info(f"Use first item of {candidate_sdk_paths} for SDK folder")
module_relative_path = candidate_sdk_paths[0]
else:
raise RuntimeError(f"Source folder not found for SDK {sdk_name}")
return module_relative_path
def main():
global script_path
global tmp_path
global specs_path
global sdk_package_path
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %X")
script_path = path.abspath(path.dirname(sys.argv[0]))
parser = argparse.ArgumentParser(description='Requires 2 arguments, path of "input.json" and "output.json".')
parser.add_argument("paths", metavar="path", type=str, nargs=2, help='path of "input.json" or "output.json"')
args = parser.parse_args()
input_json_path = args.paths[0]
output_json_path = args.paths[1]
with open(input_json_path, "r", encoding="utf-8") as f_in:
config = json.load(f_in)
specs_path = config["specsPath"]
sdk_path = config["sdkPath"]
sdk_examples_path = config["sdkExamplesPath"]
tmp_path = config["tempPath"]
release = Release(config["release"]["tag"], config["release"]["package"], config["release"]["version"])
js_module = f"{release.package}@{release.version}"
module_relative_path_local = get_module_relative_path(release.package, sdk_path)
python_examples_relative_path = path.join(module_relative_path_local, "generated_samples")
python_examples_path = path.join(sdk_path, python_examples_relative_path)
sdk_package_path = path.join(sdk_path, module_relative_path_local)
succeeded, files = create_python_examples(release, js_module, sdk_examples_path, python_examples_path)
with open(output_json_path, "w", encoding="utf-8") as f_out:
output = {"status": "succeeded" if succeeded else "failed", "name": js_module, "files": files}
json.dump(output, f_out, indent=2)
if __name__ == "__main__":
main()