From 51f2b9203d29a0794ba7b87e88e634b16c773bd4 Mon Sep 17 00:00:00 2001 From: Tomoya Tanjo Date: Tue, 9 Nov 2021 23:03:30 +0900 Subject: [PATCH] Fix #473: Add `--codegen-parser-info` (#476) * Use `package` as parse info if `parser_info` is not provided --- schema_salad/codegen.py | 19 ++++++++++-- schema_salad/java_codegen.py | 12 ++------ schema_salad/main.py | 9 ++++++ schema_salad/metaschema.py | 4 +++ schema_salad/python_codegen.py | 16 ++++++++++- schema_salad/tests/test_python_codegen.py | 35 +++++++++++++++++++++-- 6 files changed, 79 insertions(+), 16 deletions(-) diff --git a/schema_salad/codegen.py b/schema_salad/codegen.py index f7359199..3c4144e6 100644 --- a/schema_salad/codegen.py +++ b/schema_salad/codegen.py @@ -11,6 +11,7 @@ TextIO, Union, ) +from urllib.parse import urlsplit from . import schema from .codegen_base import CodeGenBase @@ -33,12 +34,23 @@ def codegen( examples: Optional[str] = None, package: Optional[str] = None, copyright: Optional[str] = None, + parser_info: Optional[str] = None, ) -> None: """Generate classes with loaders for the given Schema Salad description.""" j = schema.extend_and_specialize(i, loader) gen = None # type: Optional[CodeGenBase] + base = schema_metadata.get("$base", schema_metadata.get("id")) + sp = urlsplit(base) + pkg = ( + package + if package + else ".".join( + list(reversed(sp.netloc.split("."))) + sp.path.strip("/").split("/") + ) + ) + info = parser_info or pkg if lang == "python": if target: dest: Union[TextIOWrapper, TextIO] = open( @@ -46,13 +58,14 @@ def codegen( ) else: dest = sys.stdout - gen = PythonCodeGen(dest, copyright=copyright) + + gen = PythonCodeGen(dest, copyright=copyright, parser_info=info) elif lang == "java": gen = JavaCodeGen( - schema_metadata.get("$base", schema_metadata.get("id")), + base, target=target, examples=examples, - package=package, + package=pkg, copyright=copyright, ) else: diff --git a/schema_salad/java_codegen.py b/schema_salad/java_codegen.py index ff3e8ec5..36c7641e 100644 --- a/schema_salad/java_codegen.py +++ b/schema_salad/java_codegen.py @@ -14,7 +14,6 @@ Set, Union, ) -from urllib.parse import urlsplit import pkg_resources @@ -129,20 +128,13 @@ def __init__( base: str, target: Optional[str], examples: Optional[str], - package: Optional[str], + package: str, copyright: Optional[str], ) -> None: super().__init__() self.base_uri = base - sp = urlsplit(base) self.examples = examples - self.package = ( - package - if package - else ".".join( - list(reversed(sp.netloc.split("."))) + sp.path.strip("/").split("/") - ) - ) + self.package = package self.artifact = self.package.split(".")[-1] self.copyright = copyright self.target_dir = Path(target or ".").resolve() diff --git a/schema_salad/main.py b/schema_salad/main.py index 04b972e8..4dca459b 100644 --- a/schema_salad/main.py +++ b/schema_salad/main.py @@ -129,6 +129,14 @@ def arg_parser() -> argparse.ArgumentParser: help="Optional copyright of the input schema.", ), + parser.add_argument( + "--codegen-parser-info", + metavar="parser_info", + type=str, + default=None, + help="Optional parser name which is accessible via resulted parser API (Python only)", + ) + exgroup.add_argument( "--print-oneline", action="store_true", @@ -323,6 +331,7 @@ def main(argsl: Optional[List[str]] = None) -> int: examples=args.codegen_examples, package=args.codegen_package, copyright=args.codegen_copyright, + parser_info=args.codegen_parser_info, ) return 0 diff --git a/schema_salad/metaschema.py b/schema_salad/metaschema.py index 8be526db..0d390203 100644 --- a/schema_salad/metaschema.py +++ b/schema_salad/metaschema.py @@ -674,6 +674,10 @@ def save_relative_uri( return save(uri, top=False, base_url=base_url) +def parser_info() -> str: + return "org.w3id.cwl.salad" + + class Documented(Savable): pass diff --git a/schema_salad/python_codegen.py b/schema_salad/python_codegen.py index 984a93dc..458806e4 100644 --- a/schema_salad/python_codegen.py +++ b/schema_salad/python_codegen.py @@ -68,13 +68,19 @@ def fmt(text: str, indent: int) -> str: class PythonCodeGen(CodeGenBase): """Generation of Python code for a given Schema Salad definition.""" - def __init__(self, out: IO[str], copyright: Optional[str]) -> None: + def __init__( + self, + out: IO[str], + copyright: Optional[str], + parser_info: str, + ) -> None: super().__init__() self.out = out self.current_class_is_abstract = False self.serializer = StringIO() self.idfield = "" self.copyright = copyright + self.parser_info = parser_info @staticmethod def safe_name(name: str) -> str: @@ -112,6 +118,14 @@ def prologue(self) -> None: stream.close() self.out.write("\n\n") + self.out.write( + f"""def parser_info() -> str: + return "{self.parser_info}" + + +""" + ) + for primative in prims.values(): self.declare_type(primative) diff --git a/schema_salad/tests/test_python_codegen.py b/schema_salad/tests/test_python_codegen.py index 6f0dee4e..dcb11798 100644 --- a/schema_salad/tests/test_python_codegen.py +++ b/schema_salad/tests/test_python_codegen.py @@ -1,7 +1,7 @@ import inspect import os from pathlib import Path -from typing import Any, Dict, List, cast +from typing import Any, Dict, List, Optional, cast import schema_salad.metaschema as cg_metaschema from schema_salad import codegen @@ -35,7 +35,12 @@ def test_meta_schema_gen_up_to_date(tmp_path: Path) -> None: assert f.read() == inspect.getsource(cg_metaschema) -def python_codegen(file_uri: str, target: Path) -> None: +def python_codegen( + file_uri: str, + target: Path, + parser_info: Optional[str] = None, + package: Optional[str] = None, +) -> None: document_loader, avsc_names, schema_metadata, metaschema_loader = load_schema( file_uri ) @@ -50,4 +55,30 @@ def python_codegen(file_uri: str, target: Path) -> None: schema_metadata, document_loader, target=str(target), + parser_info=parser_info, + package=package, ) + + +def test_default_parser_info(tmp_path: Path) -> None: + src_target = tmp_path / "src.py" + python_codegen(metaschema_file_uri, src_target) + assert os.path.exists(src_target) + with open(src_target) as f: + assert 'def parser_info() -> str:\n return "org.w3id.cwl.salad"' in f.read() + + +def test_parser_info(tmp_path: Path) -> None: + src_target = tmp_path / "src.py" + python_codegen(metaschema_file_uri, src_target, parser_info="cwl") + assert os.path.exists(src_target) + with open(src_target) as f: + assert 'def parser_info() -> str:\n return "cwl"' in f.read() + + +def test_use_of_package_for_parser_info(tmp_path: Path) -> None: + src_target = tmp_path / "src.py" + python_codegen(metaschema_file_uri, src_target, package="cwl") + assert os.path.exists(src_target) + with open(src_target) as f: + assert 'def parser_info() -> str:\n return "cwl"' in f.read()