Example #1
0
def generate_schema(class_name, schema):
    """
    Generate C# declaration file for a schema.
    """
    has_map = False
    for field in schema["fields"]:
        if field["type"].startswith("Map"): has_map = True

    superclass = schema["superclass"]
    if superclass == "Iced": superclass = "Object"

    yield "/**"
    yield " * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_csharp.py"
    yield " * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield " */"
    yield "namespace ai.h2o"
    yield "{"
    yield "  using System;"
    yield "  using System.Collections.Generic;" if has_map else None
    yield ""
    yield "  public class {name}: {super} {{".format(name=class_name, super=superclass)

    for field in schema["fields"]:
        if field["name"] == "__meta": continue
        csharp_type = translate_type(field["type"], field["schema_name"])
        yield "    /// <summary>"
        yield bi.wrap(field["help"], "    ///   ")
        yield "    /// </summary>"
        yield "    public {type} {name} {{ get; set; }}".format(type=csharp_type, name=field["name"])
        yield ""

    yield "  }"
    yield "}"
Example #2
0
def generate_schema(class_name, schema):
    """
    Generate C# declaration file for a schema.
    """
    has_map = False
    for field in schema["fields"]:
        if field["type"].startswith("Map"): has_map = True

    superclass = schema["superclass"]
    if superclass == "Iced": superclass = "Object"

    yield "/**"
    yield " * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_csharp.py"
    yield " * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield " */"
    yield "namespace ai.h2o"
    yield "{"
    yield "  using System;"
    yield "  using System.Collections.Generic;" if has_map else None
    yield ""
    yield "  public class {name}: {super} {{".format(name=class_name,
                                                     super=superclass)

    for field in schema["fields"]:
        if field["name"] == "__meta": continue
        csharp_type = translate_type(field["type"], field["schema_name"])
        yield "    /// <summary>"
        yield bi.wrap(field["help"], "    ///   ")
        yield "    /// </summary>"
        yield "    public {type} {name} {{ get; set; }}".format(
            type=csharp_type, name=field["name"])
        yield ""

    yield "  }"
    yield "}"
Example #3
0
def gen_init(modules):
    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    yield "import inspect"
    yield "import sys"
    yield ""
    module_strs = []
    # imports estimators
    for full_module, module, clz, category in sorted(modules):
        if module in ["grid", "automl"]:
            continue
        module_strs.append('"%s"' % clz)
        yield "from .%s import %s" % (module, clz)
    # global methods for h2o.estimators module
    yield """

module = sys.modules[__name__]


def _algo_for_estimator_(shortname, cls):
    if shortname == 'H2OAutoEncoderEstimator':
        return 'autoencoder'
    return cls.algo


_estimator_cls_by_algo_ = {_algo_for_estimator_(name, cls): cls
                           for name, cls in inspect.getmembers(module, inspect.isclass)
                           if hasattr(cls, 'algo')}


def create_estimator(algo, **params):
    if algo not in _estimator_cls_by_algo_:
        raise ValueError("Unknown algo type: " + algo)
    return _estimator_cls_by_algo_[algo](**params)

"""
    # auto-exports
    yield "__all__ = ("
    yield bi.wrap('"create_estimator",', indent=" " * 4)
    yield bi.wrap(", ".join(module_strs), indent=" " * 4)
    yield ")"
Example #4
0
def gen_init(modules):
    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    for module, clz in modules:
        yield "from .%s import %s" % (module, clz)
    yield ""
    yield "__all__ = ["
    yield bi.wrap(", ".join('"%s"' % clz for _, clz in modules), indent="    ")
    yield "]"
Example #5
0
def gen_init(modules):
    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    for module, clz in modules:
        yield "from .%s import %s" % (module, clz)
    yield ""
    yield "__all__ = ["
    yield bi.wrap(", ".join('"%s"' % clz for _, clz in modules), indent="    ")
    yield "]"
Example #6
0
def get_help(param, indent=0):
    pname = param.get('name')
    ptype = param.get('type')
    pvalues = param.get('values')
    pdefault = param.get('default_value')
    phelp = param.get('help')
    if not phelp:
        return
    if ptype == 'boolean':
        phelp = "\code{Logical}. " + phelp
    if pvalues:
        phelp += " Must be one of: %s." % ", ".join('"%s"' % v for v in pvalues)
    if pdefault is not None:
        phelp += " Defaults to %s." % get_doc_default_value(param)
    return bi.wrap(phelp, width=120-indent)
Example #7
0
def gen_init(modules):
    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    module_strs = []
    for module, clz, category in sorted(modules):
        if clz == "H2OGridSearch": continue
        module_strs.append('"%s"' % clz)
        yield "from .%s import %s" % (module, clz)
    yield ""
    yield "__all__ = ("
    yield bi.wrap(", ".join(module_strs), indent="    ")
    yield ")"
Example #8
0
def generate_struct(name, schema):
    bi.vprint("Generating struct " + name)
    yield "struct %s {" % name
    yield ""
    for i, field in enumerate(schema["fields"]):
        if field["name"] == "__meta": continue
        thrift_type = translate_type(field["type"], field["schema_name"])
        name = field["name"]
        if name in thrift_reserved_words:
            name += "_"
        required = "required" if field["required"] else "optional"
        yield bi.wrap(field["help"], indent="  # ")
        yield "  {num}: {req} {type} {name},".format(num=i, req=required, type=thrift_type, name=name)
        yield ""
    yield "}"
    yield ""
Example #9
0
def gen_init(modules):
    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    module_strs = []
    for module, clz, category in sorted(modules):
        if clz == "H2OGridSearch": continue
        module_strs.append('"%s"' % clz)
        if clz == "H2OAutoML": continue
        module_strs.append('"%s"' % clz)
        yield "from .%s import %s" % (module, clz)
    yield ""
    yield "__all__ = ("
    yield bi.wrap(", ".join(module_strs), indent="    ")
    yield ")"
Example #10
0
def generate_struct(name, schema):
    bi.vprint("Generating struct " + name)
    yield "struct %s {" % name
    yield ""
    for i, field in enumerate(schema["fields"]):
        if field["name"] == "__meta": continue
        thrift_type = translate_type(field["type"], field["schema_name"])
        name = field["name"]
        if name in thrift_reserved_words:
            name += "_"
        required = "required" if field["required"] else "optional"
        yield bi.wrap(field["help"], indent="  # ")
        yield "  {num}: {req} {type} {name},".format(num=i,
                                                     req=required,
                                                     type=thrift_type,
                                                     name=name)
        yield ""
    yield "}"
    yield ""
Example #11
0
def gen_module(schema, algo):
    classname = algo_to_classname(algo)
    extra_imports = extra_imports_for(algo)
    help_preamble = help_preamble_for(algo)
    help_epilogue = help_epilogue_for(algo)
    init_extra = init_extra_for(algo)
    class_extra = class_extra_for(algo)
    module_extra = module_extra_for(algo)

    param_names = []
    for param in schema["parameters"]:
        assert (param["type"][:4] == "enum") == bool(param["values"]), "Values are expected for enum types only"
        if param["values"]:
            enum_values = [normalize_enum_constant(p) for p in param["values"]]
            if param["default_value"]:
                param["default_value"] = normalize_enum_constant(param["default_value"])
        else:
            enum_values = None
        pname = param["name"]
        if pname in reserved_words: pname += "_"
        param_names.append(pname)
        param["pname"] = pname
        param["ptype"] = translate_type_for_check(param["type"], enum_values)
        param["dtype"] = translate_type_for_doc(param["type"], enum_values)

    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    yield "from __future__ import absolute_import, division, print_function, unicode_literals"
    yield ""
    yield "from h2o.estimators.estimator_base import H2OEstimator"
    yield "from h2o.exceptions import H2OValueError"
    yield "from h2o.frame import H2OFrame"
    if classname == "H2OStackedEnsembleEstimator":
        yield "from h2o.utils.typechecks import assert_is_type, Enum, numeric, is_type"
    else:
        yield "from h2o.utils.typechecks import assert_is_type, Enum, numeric"
    if extra_imports:
        yield reindent_block(extra_imports, 0) + ""
    yield ""
    yield ""
    yield "class %s(H2OEstimator):" % classname
    yield "    \"\"\""
    yield "    " + schema["algo_full_name"]
    yield ""
    if help_preamble:
        yield "    %s" % reindent_block(help_preamble, 4)
    if help_epilogue:
        yield ""
        yield "    %s" % reindent_block(help_epilogue, 4)
    yield "    \"\"\""
    yield ""
    yield '    algo = "%s"' % algo
    yield ""
    yield "    def __init__(self, **kwargs):"
    yield "        super(%s, self).__init__()" % classname
    yield "        self._parms = {}"
    yield "        names_list = {%s}" % bi.wrap(", ".join('"%s"' % p for p in param_names),
                                                indent=(" " * 22), indent_first=False)
    yield '        if "Lambda" in kwargs: kwargs["lambda_"] = kwargs.pop("Lambda")'
    yield "        for pname, pvalue in kwargs.items():"
    yield "            if pname == 'model_id':"
    yield "                self._id = pvalue"
    yield '                self._parms["model_id"] = pvalue'
    yield "            elif pname in names_list:"
    yield "                # Using setattr(...) will invoke type-checking of the arguments"
    yield "                setattr(self, pname, pvalue)"
    yield "            else:"
    yield '                raise H2OValueError("Unknown parameter %s = %r" % (pname, pvalue))'
    if init_extra:
        yield "        " + reindent_block(init_extra, 8)
    yield ""
    for param in schema["parameters"]:
        pname = param["pname"]
        ptype = param["ptype"]
        if pname == "model_id": continue  # The getter is already defined in ModelBase
        sname = pname[:-1] if pname[-1] == '_' else pname

        if param["dtype"].startswith("Enum"):
            vals = param["dtype"][5:-1].split(", ")
            extrahelp = "One of: " + ", ".join("``%s``" % v for v in vals)
        else:
            extrahelp = "Type: ``%s``" % param["dtype"]
        if param["default_value"] is None:
            extrahelp += "."
        else:
            extrahelp += "  (default: ``%s``)." % stringify(param["default_value"])

        yield "    @property"
        yield "    def %s(self):" % pname
        yield '        """'
        yield "        %s" % bi.wrap(param["help"], indent=(" " * 8), indent_first=False)
        yield ""
        yield "        %s" % bi.wrap(extrahelp, indent=(" " * 8), indent_first=False)
        yield '        """'
        yield "        return self._parms.get(\"%s\")" % sname
        yield ""
        yield "    @%s.setter" % pname
        yield "    def %s(self, %s):" % (pname, pname)
        if pname in {"initial_weights", "initial_biases"}:
            yield "        assert_is_type(%s, None, [H2OFrame, None])" % pname
        elif pname in {"alpha", "lambda_"} and ptype == "[numeric]":
            # For `alpha` and `lambda` the server reports type float[], while in practice simple floats are also ok
            yield "        assert_is_type(%s, None, numeric, [numeric])" % pname
        elif pname in {"checkpoint", "pretrained_autoencoder"}:
            yield "        assert_is_type(%s, None, str, H2OEstimator)" % pname
        elif pname in {"base_models"}:
            yield "         if is_type(base_models,[H2OEstimator]):"
            yield      "            %s = [b.model_id for b in %s]" % (pname,pname)
            yield      "            self._parms[\"%s\"] = %s" % (sname, pname)
            yield "         else:"
            yield "            assert_is_type(%s, None, %s)" % (pname, ptype)
            yield "            self._parms[\"%s\"] = %s" % (sname, pname)
        else:
            yield "        assert_is_type(%s, None, %s)" % (pname, ptype)
        if pname not in {"base_models"}:
            yield "        self._parms[\"%s\"] = %s" % (sname, pname)
        yield ""
        yield ""
    if class_extra:
        yield ""
        yield "    " + reindent_block(class_extra, 4)
    if module_extra:
        yield ""
        yield reindent_block(module_extra, 0)
Example #12
0
def gen_module(schema, algo):
    classname = algo_to_classname(algo)
    extra_imports = extra_imports_for(algo)
    help_preamble = help_preamble_for(algo)
    help_epilogue = help_epilogue_for(algo)
    init_extra = init_extra_for(algo)
    class_extra = class_extra_for(algo)
    module_extra = module_extra_for(algo)

    param_names = []
    for param in schema["parameters"]:
        assert (param["type"][:4] == "enum") == bool(param["values"]), "Values are expected for enum types only"
        if param["values"]:
            enum_values = [normalize_enum_constant(p) for p in param["values"]]
            if param["default_value"]:
                param["default_value"] = normalize_enum_constant(param["default_value"])
        else:
            enum_values = None
        pname = param["name"]
        if (pname==u'distribution') and (not(algo==u'glm') and not(algo==u'gbm')):    # quasibinomial only in glm, gbm
            enum_values.remove(u'quasibinomial')
        if (pname==u'distribution') and (not(algo==u'glm')):    # ordinal only in glm
            enum_values.remove(u'ordinal')
        if pname in reserved_words: pname += "_"
        param_names.append(pname)
        param["pname"] = pname
        param["ptype"] = translate_type_for_check(param["type"], enum_values)
        param["dtype"] = translate_type_for_doc(param["type"], enum_values)

    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    yield "from __future__ import absolute_import, division, print_function, unicode_literals"
    yield ""
    yield "from h2o.estimators.estimator_base import H2OEstimator"
    yield "from h2o.exceptions import H2OValueError"
    yield "from h2o.frame import H2OFrame"
    if classname == "H2OStackedEnsembleEstimator":
        yield "from h2o.utils.typechecks import assert_is_type, Enum, numeric, is_type"
        yield "import json"
        yield "import ast"
    else:
        yield "from h2o.utils.typechecks import assert_is_type, Enum, numeric"
    if extra_imports:
        yield reindent_block(extra_imports, 0) + ""
    yield ""
    yield ""
    yield "class %s(H2OEstimator):" % classname
    yield "    \"\"\""
    yield "    " + schema["algo_full_name"]
    yield ""
    if help_preamble:
        yield "    %s" % reindent_block(help_preamble, 4)
    if help_epilogue:
        yield ""
        yield "    %s" % reindent_block(help_epilogue, 4)
    yield "    \"\"\""
    yield ""
    yield '    algo = "%s"' % algo
    yield ""
    yield "    def __init__(self, **kwargs):"
    yield "        super(%s, self).__init__()" % classname
    yield "        self._parms = {}"
    yield "        names_list = {%s}" % bi.wrap(", ".join('"%s"' % p for p in param_names),
                                                indent=(" " * 22), indent_first=False)
    yield '        if "Lambda" in kwargs: kwargs["lambda_"] = kwargs.pop("Lambda")'
    yield "        for pname, pvalue in kwargs.items():"
    yield "            if pname == 'model_id':"
    yield "                self._id = pvalue"
    yield '                self._parms["model_id"] = pvalue'
    if algo == 'word2vec':
        yield '            elif pname == \'pre_trained\':'
        yield '                setattr(self, pname, pvalue)'
        yield '                self._determine_vec_size();'
        yield '                setattr(self, \'vec_size\', self.vec_size)'
    yield "            elif pname in names_list:"
    yield "                # Using setattr(...) will invoke type-checking of the arguments"
    yield "                setattr(self, pname, pvalue)"
    yield "            else:"
    yield '                raise H2OValueError("Unknown parameter %s = %r" % (pname, pvalue))'
    if init_extra:
        yield "        " + reindent_block(init_extra, 8)
    yield ""
    for param in schema["parameters"]:
        pname = param["pname"]
        ptype = param["ptype"]
        if pname == "model_id": continue  # The getter is already defined in ModelBase
        sname = pname[:-1] if pname[-1] == '_' else pname

        if param["dtype"].startswith("Enum"):
            vals = param["dtype"][5:-1].split(", ")
            extrahelp = "One of: " + ", ".join("``%s``" % v for v in vals)
        else:
            if pname == "metalearner_params":
                extrahelp = "Type: ``dict``"
            else:
                extrahelp = "Type: ``%s``" % param["dtype"]
        if param["default_value"] is None:
            extrahelp += "."
        else:
            if pname == "metalearner_params":
                extrahelp += "  (default: ``None``)."
            else:
                extrahelp += "  (default: ``%s``)." % stringify(param["default_value"])

        if (pname == "offset_column" or pname == "distribution") and algo == "drf":
            yield "    @property"
            yield "    def %s(self):" % pname
            yield '        """'
            yield "        [Deprecated] %s" % bi.wrap(param["help"], indent=(" " * 8), indent_first=False)
            yield ""
            yield "        %s" % bi.wrap(extrahelp, indent=(" " * 8), indent_first=False)
        else:
            yield "    @property"
            yield "    def %s(self):" % pname
            yield '        """'
            yield "        %s" % bi.wrap(param["help"], indent=(" " * 8), indent_first=False)
            yield ""
            yield "        %s" % bi.wrap(extrahelp, indent=(" " * 8), indent_first=False)
        if pname == "metalearner_params":
            yield "        Example: metalearner_gbm_params = {'max_depth': 2, 'col_sample_rate': 0.3}"
        yield '        """'
        if pname != "metalearner_params":
            yield "        return self._parms.get(\"%s\")" % sname
        else:
            yield "        if self._parms.get(\"%s\") != None:" % sname
            yield "            metalearner_params_dict =  ast.literal_eval(self._parms.get(\"%s\"))" % sname
            yield "            for k in metalearner_params_dict:"
            yield "                if len(metalearner_params_dict[k]) == 1: #single parameter"
            yield "                    metalearner_params_dict[k] = metalearner_params_dict[k][0]"
            yield "            return metalearner_params_dict"
            yield "        else:"
            yield "            return self._parms.get(\"%s\")" % sname
        yield ""
        yield "    @%s.setter" % pname
        yield "    def %s(self, %s):" % (pname, pname)
        if pname in {"initial_weights", "initial_biases"}:
            yield "        assert_is_type(%s, None, [H2OFrame, None])" % pname
        elif pname in {"alpha", "lambda_"} and ptype == "[numeric]":
            # For `alpha` and `lambda` the server reports type float[], while in practice simple floats are also ok
            yield "        assert_is_type(%s, None, numeric, [numeric])" % pname
        elif pname in {"checkpoint", "pretrained_autoencoder"}:
            yield "        assert_is_type(%s, None, str, H2OEstimator)" % pname
        elif pname in {"base_models"}:
            yield "         if is_type(base_models,[H2OEstimator]):"
            yield      "            %s = [b.model_id for b in %s]" % (pname,pname)
            yield      "            self._parms[\"%s\"] = %s" % (sname, pname)
            yield "         else:"
            yield "            assert_is_type(%s, None, %s)" % (pname, ptype)
            yield "            self._parms[\"%s\"] = %s" % (sname, pname)
        elif pname in {"metalearner_params"}:
            yield "        assert_is_type(%s, None, %s)" % (pname, "dict")
            yield '        if %s is not None and %s != "":' % (pname, pname)
            yield "            for k in %s:" % (pname)
            yield '                if ("[" and "]") not in str(metalearner_params[k]):'
            yield "                    metalearner_params[k]=[metalearner_params[k]]"
            yield "            self._parms[\"%s\"] = str(json.dumps(%s))" % (sname, pname)
            yield "        else:"
            yield "            self._parms[\"%s\"] = None" % (sname)
        else:
            yield "        assert_is_type(%s, None, %s)" % (pname, ptype)
        if pname not in {"base_models", "metalearner_params"}:
            yield "        self._parms[\"%s\"] = %s" % (sname, pname)
        yield ""
        yield ""
    if class_extra:
        yield ""
        yield "    " + reindent_block(class_extra, 4)
    if module_extra:
        yield ""
        yield reindent_block(module_extra, 0)
Example #13
0
def gen_module(schema, algo):
    classname = algo_to_classname(algo)
    extra_imports = extra_imports_for(algo)
    help_preamble = help_preamble_for(algo)
    help_epilogue = help_epilogue_for(algo)
    init_extra = init_extra_for(algo)
    class_extra = class_extra_for(algo)
    module_extra = module_extra_for(algo)

    param_names = []
    for param in schema["parameters"]:
        assert (param["type"][:4] == "enum") == bool(
            param["values"]), "Values are expected for enum types only"
        if param["values"]:
            enum_values = [normalize_enum_constant(p) for p in param["values"]]
            if param["default_value"]:
                param["default_value"] = normalize_enum_constant(
                    param["default_value"])
        else:
            enum_values = None
        pname = param["name"]
        if (pname == u'distribution') and (
                not (algo == u'glm')
                and not (algo == u'gbm')):  # quasibinomial only in glm, gbm
            enum_values.remove(u'quasibinomial')
        if (pname == u'distribution') and (
                not (algo == u'glm')):  # ordinal only in glm
            enum_values.remove(u'ordinal')
        if (pname == u'distribution') and (
                not (algo == u'gbm')):  # custom only in gbm
            enum_values.remove(u'custom')
        if (pname == u'stopping_metric') and (
                not (algo == u'isolationforest')
        ):  # anomaly_score only in Isolation Forest
            enum_values.remove(u'anomaly_score')
        if (pname == u'stopping_metric') and (algo == u'isolationforest'):
            enum_values = [u'AUTO', u'anomaly_score']
        if pname in reserved_words: pname += "_"
        param_names.append(pname)
        param["pname"] = pname
        param["ptype"] = translate_type_for_check(param["type"], enum_values)
        param["dtype"] = translate_type_for_doc(param["type"], enum_values)

    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    yield "from __future__ import absolute_import, division, print_function, unicode_literals"
    yield ""
    yield "from h2o.estimators.estimator_base import H2OEstimator"
    yield "from h2o.exceptions import H2OValueError"
    yield "from h2o.frame import H2OFrame"
    if classname == "H2OStackedEnsembleEstimator":
        yield "from h2o.utils.typechecks import assert_is_type, Enum, numeric, is_type"
        yield "import json"
        yield "import ast"
    else:
        yield "from h2o.utils.typechecks import assert_is_type, Enum, numeric"
    if extra_imports:
        yield reindent_block(extra_imports, 0) + ""
    yield ""
    yield ""
    yield "class %s(H2OEstimator):" % classname
    yield "    \"\"\""
    yield "    " + schema["algo_full_name"]
    yield ""
    if help_preamble:
        yield "    %s" % reindent_block(help_preamble, 4)
    if help_epilogue:
        yield ""
        yield "    %s" % reindent_block(help_epilogue, 4)
    yield "    \"\"\""
    yield ""
    yield '    algo = "%s"' % algo
    yield ""
    yield "    def __init__(self, **kwargs):"
    yield "        super(%s, self).__init__()" % classname
    yield "        self._parms = {}"
    yield "        names_list = {%s}" % bi.wrap(", ".join(
        '"%s"' % p for p in param_names),
                                                indent=(" " * 22),
                                                indent_first=False)
    yield '        if "Lambda" in kwargs: kwargs["lambda_"] = kwargs.pop("Lambda")'
    yield "        for pname, pvalue in kwargs.items():"
    yield "            if pname == 'model_id':"
    yield "                self._id = pvalue"
    yield '                self._parms["model_id"] = pvalue'
    if algo == 'word2vec':
        yield '            elif pname == \'pre_trained\':'
        yield '                setattr(self, pname, pvalue)'
        yield '                self._determine_vec_size();'
        yield '                setattr(self, \'vec_size\', self.vec_size)'
    yield "            elif pname in names_list:"
    yield "                # Using setattr(...) will invoke type-checking of the arguments"
    yield "                setattr(self, pname, pvalue)"
    yield "            else:"
    yield '                raise H2OValueError("Unknown parameter %s = %r" % (pname, pvalue))'
    if init_extra:
        yield "        " + reindent_block(init_extra, 8)
    yield ""
    for param in schema["parameters"]:
        pname = param["pname"]
        ptype = param["ptype"]
        if pname == "model_id":
            continue  # The getter is already defined in ModelBase
        sname = pname[:-1] if pname[-1] == '_' else pname

        if param["dtype"].startswith("Enum"):
            vals = param["dtype"][5:-1].split(", ")
            extrahelp = "One of: " + ", ".join("``%s``" % v for v in vals)
        else:
            if pname == "metalearner_params":
                extrahelp = "Type: ``dict``"
            else:
                extrahelp = "Type: ``%s``" % param["dtype"]
        if param["default_value"] is None:
            extrahelp += "."
        else:
            if pname == "metalearner_params":
                extrahelp += "  (default: ``None``)."
            else:
                extrahelp += "  (default: ``%s``)." % stringify(
                    param["default_value"])

        if (pname == "offset_column"
                or pname == "distribution") and algo == "drf":
            yield "    @property"
            yield "    def %s(self):" % pname
            yield '        """'
            yield "        [Deprecated] %s" % bi.wrap(
                param["help"], indent=(" " * 8), indent_first=False)
            yield ""
            yield "        %s" % bi.wrap(
                extrahelp, indent=(" " * 8), indent_first=False)
        else:
            yield "    @property"
            yield "    def %s(self):" % pname
            yield '        """'
            yield "        %s" % bi.wrap(
                param["help"], indent=(" " * 8), indent_first=False)
            yield ""
            yield "        %s" % bi.wrap(
                extrahelp, indent=(" " * 8), indent_first=False)
        if pname == "metalearner_params":
            yield "        Example: metalearner_gbm_params = {'max_depth': 2, 'col_sample_rate': 0.3}"
        yield '        """'
        if pname != "metalearner_params":
            yield "        return self._parms.get(\"%s\")" % sname
        else:
            yield "        if self._parms.get(\"%s\") != None:" % sname
            yield "            metalearner_params_dict =  ast.literal_eval(self._parms.get(\"%s\"))" % sname
            yield "            for k in metalearner_params_dict:"
            yield "                if len(metalearner_params_dict[k]) == 1: #single parameter"
            yield "                    metalearner_params_dict[k] = metalearner_params_dict[k][0]"
            yield "            return metalearner_params_dict"
            yield "        else:"
            yield "            return self._parms.get(\"%s\")" % sname
        yield ""
        yield "    @%s.setter" % pname
        yield "    def %s(self, %s):" % (pname, pname)
        if pname in {"initial_weights", "initial_biases"}:
            yield "        assert_is_type(%s, None, [H2OFrame, None])" % pname
        elif pname in {"alpha", "lambda_"} and ptype == "[numeric]":
            # For `alpha` and `lambda` the server reports type float[], while in practice simple floats are also ok
            yield "        assert_is_type(%s, None, numeric, [numeric])" % pname
        elif pname in {"checkpoint", "pretrained_autoencoder"}:
            yield "        assert_is_type(%s, None, str, H2OEstimator)" % pname
        elif pname in {"base_models"}:
            yield "         if is_type(base_models,[H2OEstimator]):"
            yield "            %s = [b.model_id for b in %s]" % (pname, pname)
            yield "            self._parms[\"%s\"] = %s" % (sname, pname)
            yield "         else:"
            yield "            assert_is_type(%s, None, %s)" % (pname, ptype)
            yield "            self._parms[\"%s\"] = %s" % (sname, pname)
        elif pname in {"metalearner_params"}:
            yield "        assert_is_type(%s, None, %s)" % (pname, "dict")
            yield '        if %s is not None and %s != "":' % (pname, pname)
            yield "            for k in %s:" % (pname)
            yield '                if ("[" and "]") not in str(metalearner_params[k]):'
            yield "                    metalearner_params[k]=[metalearner_params[k]]"
            yield "            self._parms[\"%s\"] = str(json.dumps(%s))" % (
                sname, pname)
            yield "        else:"
            yield "            self._parms[\"%s\"] = None" % (sname)
        elif ptype == "H2OFrame":
            yield "        self._parms[\"%s\"] = H2OFrame._validate(%s, '%s')" % (
                sname, pname, pname)
        else:
            yield "        assert_is_type(%s, None, %s)" % (pname, ptype)
        if pname not in {"base_models", "metalearner_params"
                         } and ptype != "H2OFrame":
            yield "        self._parms[\"%s\"] = %s" % (sname, pname)
        yield ""
        yield ""
    if class_extra:
        yield ""
        yield "    " + reindent_block(class_extra, 4)
    if module_extra:
        yield ""
        yield reindent_block(module_extra, 0)
Example #14
0
def gen_module(schema, name):
    classname = algo_to_classname(name)
    extra_imports = extra_imports_for(name)
    help_preamble = help_preamble_for(name)
    help_epilogue = help_epilogue_for(name)
    init_extra = init_extra_for(name)
    class_extra = class_extra_for(name)
    module_extra = module_extra_for(name)

    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    yield "from .estimator_base import H2OEstimator"
    if extra_imports:
        yield reindent_block(extra_imports, 0) + ""
    yield ""
    yield ""
    yield "class %s(H2OEstimator):" % classname
    yield "    \"\"\""
    yield "    " + schema["algo_full_name"]
    yield "    " + ("-" * len(schema["algo_full_name"]))
    if help_preamble:
        yield "    %s" % reindent_block(help_preamble, 4)
    yield ""
    yield "    Parameters (optional, unless specified otherwise)"
    yield "    ----------"
    param_names = []
    for param in schema["parameters"]:
        assert (param["type"][:4] == "enum") == bool(param["values"]), "Values are expected for enum types only"
        ptype = translate_type(param["type"], param["values"])
        name = param["name"]
        if name in reserved_words: name += "_"
        param_names.append(name)
        if param["required"]: ptype += ", required"
        yield "      %s : %s" % (name, bi.wrap(ptype, " " * (9 + len(name)), indent_first=False))
        yield bi. wrap(param["help"], " " * 8)
        if param["default_value"] is not None:
            yield "        Default: %s" % stringify(param["default_value"])
        yield ""
    if help_epilogue:
        yield "    %s" % reindent_block(help_epilogue, 4)
    yield "    \"\"\""
    yield "    def __init__(self, **kwargs):"
    yield "        super(%s, self).__init__()" % classname
    yield "        self._parms = {}"
    yield "        for name in [" + bi.wrap(", ".join('"%s"' % p for p in param_names),
                                            indent=(" " * 21), indent_first=False) + "]:"
    yield "            pname = name[:-1] if name[-1] == '_' else name"
    yield "            self._parms[pname] = kwargs[name] if name in kwargs else None"
    if init_extra:
        yield "        " + reindent_block(init_extra, 8)
    yield ""
    for param in schema["parameters"]:
        name = param["name"]
        if name == "model_id": continue  # The getter is already defined in ModelBase
        prop = name
        if name in reserved_words: prop += "_"
        yield "    @property"
        yield "    def %s(self):" % prop
        yield "        return self._parms[\"%s\"]" % name
        yield ""
        yield "    @%s.setter" % prop
        yield "    def %s(self, value):" % prop
        yield "        self._parms[\"%s\"] = value" % name
        yield ""
    if class_extra:
        yield "    " + reindent_block(class_extra, 4)
        yield ""
    if module_extra:
        yield reindent_block(module_extra, 0)
        yield ""
Example #15
0
def gen_module(schema, algo):
    classname = algo_to_classname(algo)
    extra_imports = extra_imports_for(algo)
    help_preamble = help_preamble_for(algo)
    help_epilogue = help_epilogue_for(algo)
    init_extra = init_extra_for(algo)
    class_extra = class_extra_for(algo)
    module_extra = module_extra_for(algo)

    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    yield "from .estimator_base import H2OEstimator"
    if extra_imports:
        yield reindent_block(extra_imports, 0) + ""
    yield ""
    yield ""
    yield "class %s(H2OEstimator):" % classname
    yield "    \"\"\""
    yield "    " + schema["algo_full_name"]
    yield ""
    if help_preamble:
        yield "    %s" % reindent_block(help_preamble, 4)
    yield ""
    yield "    Parameters"
    yield "    ----------"
    param_names = []
    for param in schema["parameters"]:
        assert (param["type"][:4] == "enum") == bool(param["values"]), "Values are expected for enum types only"
        ptype = translate_type(param["type"], param["values"])
        name = param["name"]
        if name in reserved_words: name += "_"
        param_names.append(name)
        if param["required"]: ptype += ", required"
        yield "      %s : %s" % (name, bi.wrap(ptype, " " * (9 + len(name)), indent_first=False))
        yield bi. wrap(param["help"], " " * 8)
        if param["default_value"] is not None:
            yield "        Default: %s" % stringify(param["default_value"])
        yield ""
    if help_epilogue:
        yield "    %s" % reindent_block(help_epilogue, 4)
    yield "    \"\"\""
    yield ""
    yield '    algo = "%s"' % algo
    yield ""
    yield "    def __init__(self, **kwargs):"
    yield "        super(%s, self).__init__()" % classname
    yield "        self._parms = {}"
    yield "        for name in [" + bi.wrap(", ".join('"%s"' % p for p in param_names),
                                            indent=(" " * 21), indent_first=False) + "]:"
    yield "            pname = name[:-1] if name[-1] == '_' else name"
    yield "            self._parms[pname] = kwargs[name] if name in kwargs else None"
    if init_extra:
        yield "        " + reindent_block(init_extra, 8)
    yield ""
    for param in schema["parameters"]:
        name = param["name"]
        if name == "model_id": continue  # The getter is already defined in ModelBase
        prop = name
        if name in reserved_words: prop += "_"
        yield "    @property"
        yield "    def %s(self):" % prop
        yield "        return self._parms[\"%s\"]" % name
        yield ""
        yield "    @%s.setter" % prop
        yield "    def %s(self, value):" % prop
        yield "        self._parms[\"%s\"] = value" % name
        yield ""
    if class_extra:
        yield "    " + reindent_block(class_extra, 4)
        yield ""
    if module_extra:
        yield reindent_block(module_extra, 0)
        yield ""
Example #16
0
def gen_module(schema, algo):
    """
    Ideally we should be able to avoid logic specific to algos in this file.
    Instead, customizations are externalized in ./python/gen_{algo}.py files.
    Logic that is specific to python types (e.g. H2OFrame, enums as list...) should however stay here
    as the type translation is done in this file.
    """
    classname = algo_to_classname(algo)
    rest_api_version = get_customizations_for(algo, 'rest_api_version')
    extra_imports = get_customizations_for(algo, 'extensions.__imports__')
    class_doc = get_customizations_for(algo, 'doc.__class__')
    class_examples = get_customizations_for(algo, 'examples.__class__')
    class_init_validation = get_customizations_for(
        algo, 'extensions.__init__validation')
    class_init_setparams = get_customizations_for(
        algo, 'extensions.__init__setparams')
    class_extras = get_customizations_for(algo, 'extensions.__class__')
    module_extras = get_customizations_for(algo, 'extensions.__module__')

    update_param_defaults = get_customizations_for('defaults', 'update_param')
    update_param = get_customizations_for(algo, 'update_param')

    def extend_schema_params(param):
        pname = param.get('name')
        param = deepcopy(param)
        updates = None
        for update_fn in [update_param, update_param_defaults]:
            if callable(update_fn):
                updates = update_fn(pname, param)
            if updates is not None:
                param = updates
                break
        # return param if isinstance(param, (list, tuple)) else [param]  # always return array to support deprecated aliases
        return param

    extended_params = [extend_schema_params(p) for p in schema['parameters']]

    param_names = []
    for param in extended_params:
        pname = param.get('name')
        ptype = param.get('type')
        pvalues = param.get('values')
        pdefault = param.get('default_value')

        assert (ptype[:4] == 'enum'
                ) == bool(pvalues), "Values are expected for enum types only"
        if pvalues:
            enum_values = [normalize_enum_constant(p) for p in pvalues]
            if pdefault:
                pdefault = normalize_enum_constant(pdefault)
        else:
            enum_values = None

        if pname in reserved_words:
            pname += "_"
        param_names.append(pname)
        param['pname'] = pname
        param['default_value'] = pdefault
        param['ptype'] = translate_type_for_check(ptype, enum_values)
        param['dtype'] = translate_type_for_doc(ptype, enum_values)

    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    yield "from __future__ import absolute_import, division, print_function, unicode_literals"
    yield ""
    if extra_imports:
        yield reformat_block(extra_imports)
    yield "from h2o.estimators.estimator_base import H2OEstimator"
    yield "from h2o.exceptions import H2OValueError"
    yield "from h2o.frame import H2OFrame"
    yield "from h2o.utils.typechecks import assert_is_type, Enum, numeric"
    yield ""
    yield ""
    yield "class %s(H2OEstimator):" % classname
    yield '    """'
    yield "    " + schema["algo_full_name"]
    yield ""
    if class_doc:
        yield reformat_block(class_doc, 4)
    if class_examples:
        yield ""
        yield "    :examples:"
        yield ""
        yield reformat_block(class_examples, 4)
    yield '    """'
    yield ""
    yield '    algo = "%s"' % algo
    yield "    param_names = {%s}" % bi.wrap(", ".join('"%s"' % p
                                                       for p in param_names),
                                             indent=(" " * 19),
                                             indent_first=False)
    yield ""
    yield "    def __init__(self, **kwargs):"
    # TODO: generate __init__ docstring with all params (also generate exact signature to support auto-completion)
    yield "        super(%s, self).__init__()" % classname
    yield "        self._parms = {}"
    if class_init_validation:
        yield reformat_block(class_init_validation, 8)
    yield "        for pname, pvalue in kwargs.items():"
    yield "            if pname == 'model_id':"
    yield "                self._id = pvalue"
    yield '                self._parms["model_id"] = pvalue'
    if class_init_setparams:
        yield reformat_block(class_init_setparams, 12)
    yield "            elif pname in self.param_names:"
    yield "                # Using setattr(...) will invoke type-checking of the arguments"
    yield "                setattr(self, pname, pvalue)"
    yield "            else:"
    yield '                raise H2OValueError("Unknown parameter %s = %r" % (pname, pvalue))'
    if rest_api_version:
        yield '        self._parms["_rest_version"] = %s' % rest_api_version
    yield ""
    for param in extended_params:
        pname = param.get('pname')
        if pname == "model_id":
            continue  # The getter is already defined in ModelBase

        sname = pname[:-1] if pname[-1] == '_' else pname
        ptype = param.get('ptype')
        dtype = param.get('dtype')
        pdefault = param.get('default_value')

        if dtype.startswith("Enum"):
            vals = dtype[5:-1].split(", ")
            property_doc = "One of: " + ", ".join("``%s``" % v for v in vals)
        else:
            property_doc = "Type: ``%s``" % dtype
        property_doc += ("." if pdefault is None else "  (default: ``%s``)." %
                         stringify(pdefault))

        deprecated = pname in get_customizations_for(algo, 'deprecated', [])
        yield "    @property"
        yield "    def %s(self):" % pname
        yield '        """'
        yield bi.wrap(
            "%s%s" %
            ("[Deprecated] " if deprecated else "", param.get('help')),
            indent=8 * ' ')  # we need to wrap only for text coming from server
        yield ""
        yield bi.wrap(property_doc, indent=8 * ' ')
        custom_property_doc = get_customizations_for(algo,
                                                     "doc.{}".format(pname))
        if custom_property_doc:
            yield ""
            yield reformat_block(custom_property_doc, 8)
        property_examples = get_customizations_for(algo,
                                                   "examples.{}".format(pname))
        if property_examples:
            yield ""
            yield "        :examples:"
            yield ""
            yield reformat_block(property_examples, 8)
        yield '        """'
        property_getter = get_customizations_for(
            algo, "overrides.{}.getter".format(
                pname))  # check gen_stackedensemble.py for an example
        if property_getter:
            yield reformat_block(property_getter.format(**locals()), 8)
        else:
            yield "        return self._parms.get(\"%s\")" % sname

        yield ""
        yield "    @%s.setter" % pname
        yield "    def %s(self, %s):" % (pname, pname)
        property_setter = get_customizations_for(
            algo, "overrides.{}.setter".format(
                pname))  # check gen_stackedensemble.py for an example
        if property_setter:
            yield reformat_block(property_setter.format(**locals()), 8)
        else:
            # special types validation
            if ptype == "H2OEstimator":
                yield "        assert_is_type(%s, None, str, %s)" % (pname,
                                                                     ptype)
            elif ptype == "H2OFrame":
                yield "        self._parms[\"%s\"] = H2OFrame._validate(%s, '%s')" % (
                    sname, pname, pname)
            else:
                # default validation
                yield "        assert_is_type(%s, None, %s)" % (pname, ptype)
            if ptype != "H2OFrame":
                # default assignment
                yield "        self._parms[\"%s\"] = %s" % (sname, pname)
        yield ""
        yield ""
    if class_extras:
        yield reformat_block(code_as_str(class_extras), 4)
    if module_extras:
        yield ""
        yield reformat_block(code_as_str(module_extras))
Example #17
0
def generate_schema(class_name, schema):
    """
    Generate schema Java class.

    :param class_name: name of the class
    :param schema: information about the class
    """
    superclass = schema["superclass"]
    if superclass == "Schema": superclass = "Object"

    has_map = False
    is_model_builder = False
    has_inherited = False
    for field in schema["fields"]:
        if field["name"] == "__meta": continue
        if field["is_inherited"]:
            has_inherited = True
            continue
        if field["type"].startswith("Map"): has_map = True
        if field["name"] == "can_build": is_model_builder = True

    fields = []
    for field in schema["fields"]:
        if field["name"] == "__meta": continue
        java_type = translate_type(field["type"], field["schema_name"])
        java_value = get_java_value(field)

        # hackery: we flatten the parameters up into the ModelBuilder schema, rather than nesting them in the
        # parameters schema class...
        if False and is_model_builder and field["name"] == "parameters":
            fields.append(("parameters", "null", "ModelParameterSchemaV3[]",
                           field["help"], field["is_inherited"]))
        else:
            fields.append((field["name"], java_value, java_type, field["help"],
                           field["is_inherited"]))

    class_decl = class_name
    if "generics" in schema:
        class_decl += "<" + ", ".join(
            "%s extends %s" % (t, long_type)
            for t, long_type in schema["generics"]) + ">"
    super_decl = superclass
    if "super_generics" in schema:
        super_decl += "<" + ", ".join(schema["super_generics"]) + ">"

    yield "/*"
    yield " * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_java.py"
    yield " * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield " */"
    yield "package water.bindings.pojos;"
    yield ""
    yield "import com.google.gson.Gson;"
    yield "import com.google.gson.annotations.*;"
    yield "import java.util.Map;" if has_map else None
    yield ""
    yield ""
    yield "public class %s extends %s {" % (
        class_decl, super_decl) if super_decl != "Object" else None
    yield "public class %s {" % (
        class_decl) if super_decl == "Object" else None
    yield ""
    for name, value, ftype, fhelp, inherited in fields:
        if inherited: continue
        ccname = translate_name(name)
        yield "    /**"
        yield bi.wrap(fhelp, indent="     * ")
        yield "     */"
        yield "    @SerializedName(\"%s\")" % name if name != ccname else None
        yield "    public %s %s;" % (ftype, ccname)
        yield ""
    if has_inherited:
        yield ""
        yield "    /*" + ("-" * 114)
        yield "    //" + (" " * 50) + "INHERITED"
        yield "    //" + ("-" * 114)
        yield ""
        for name, value, ftype, fhelp, inherited in fields:
            if not inherited: continue
            yield bi.wrap(fhelp, "    // ")
            yield "    public %s %s;" % (ftype, translate_name(name))
            yield ""
        yield "    */"
        yield ""
    yield "    /**"
    yield "     * Public constructor"
    yield "     */"
    yield "    public %s() {" % class_name
    for name, value, _, _, _ in fields:
        if name == "parameters": continue
        if value == "null": continue
        yield "        %s = %s;" % (translate_name(name), value)
    yield "    }"
    yield ""
    yield "    /**"
    yield "     * Return the contents of this object as a JSON String."
    yield "     */"
    yield "    @Override"
    yield "    public String toString() {"
    yield "        return new Gson().toJson(this);"
    yield "    }"
    yield ""
    yield "}"
Example #18
0
def generate_main_class(endpoints):
    yield dedent(
        0, """
        /*
         * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_java.py
         * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)
         */
        package water.bindings;

        import water.bindings.pojos.*;
        import water.bindings.proxies.retrofit.*;
        import retrofit2.*;
        import retrofit2.converter.gson.GsonConverterFactory;
        import com.google.gson.*;
        import com.google.gson.reflect.TypeToken;
        import com.google.gson.stream.JsonReader;
        import com.google.gson.stream.JsonWriter;
        import okhttp3.OkHttpClient;
        import java.io.IOException;
        import java.util.concurrent.TimeUnit;
        import java.lang.reflect.Array;
        import java.lang.reflect.Field;
        import java.lang.reflect.InvocationTargetException;
        import java.lang.reflect.Type;


        @SuppressWarnings("unused")
        public class H2oApi {

          public static String DEFAULT_URL = \"http://localhost:54321/\";

          public H2oApi() {
            this(DEFAULT_URL);
          }
          public H2oApi(String url) {
            _url = url;
          }

          public H2oApi setUrl(String url) {
            _url = url;
            retrofit = null;
            return this;
          }

          public H2oApi setTimeout(int t) {
            timeout_s = t;
            retrofit = null;
            return this;
          }

          /**
           * Set time interval for job polling in {@link #waitForJobCompletion(JobKeyV3)}.
           *   @param millis time interval, in milliseconds
           */
          public H2oApi setJobPollInterval(int millis) {
            pollInterval_ms = millis;
            return this;
          }

          /**
           * Continuously poll server for the status of the given job, until it completes.
           *   @param jobKey job to query
           *   @return the finished job
           */
          public JobV3 waitForJobCompletion(JobKeyV3 jobKey) {
            return waitForJobCompletion(keyToString(jobKey));
          }
          public JobV3 waitForJobCompletion(String jobId) {
            Jobs jobService = getService(Jobs.class);
            Response<JobsV3> jobsResponse = null;
            int retries = 3;
            JobsV3 jobs = null;
            do {
              try {
                Thread.sleep(pollInterval_ms);
                jobsResponse = jobService.fetch(jobId).execute();
              } catch (IOException e) {
                System.err.println(\"Caught exception: \" + e);
              } catch (InterruptedException e) { /* pass */ }
              if (jobsResponse == null || !jobsResponse.isSuccessful())
                if (retries-- > 0)
                  continue;
                else
                  throw new RuntimeException(\"/3/Jobs/\" + jobId + \" failed 3 times.\");
              jobs = jobsResponse.body();
              if (jobs.jobs == null || jobs.jobs.length != 1)
                throw new RuntimeException(\"Failed to find Job: \" + jobId);
            } while (jobs != null && jobs.jobs[0].status.equals(\"RUNNING\"));
            return jobs == null? null : jobs.jobs[0];
          }

        """)

    for route in endpoints:
        apiname = route["api_name"]
        class_name = route["class_name"]
        outtype = route["output_schema"]
        input_fields = route["input_params"]
        required_fields = [
            field for field in input_fields if field["required"]
        ]
        input_fields_wo_excluded = [
            field for field in input_fields
            if field["name"] != "_exclude_fields"
        ]

        yield "  /**"
        yield bi.wrap(route["summary"], indent="   * ")
        yield "   */"
        # Make several versions of each API call:
        #  (1) Only the required parameters
        #  (2) All parameters except the _excluded_fields
        #  (3) All parameters
        li = len(input_fields)
        le = len(input_fields_wo_excluded)
        lr = len(required_fields)
        assert lr <= 3, "Too many required fields in method " + apiname
        if lr == li:
            # The set of required fields is the same as the set of input fields. No need for (2) and (3).
            input_fields = None
            input_fields_wo_excluded = None
        elif le == li or le == lr or li >= 4:
            # If set (2) coincides with either (1) or (3), then we will not generate code for it.
            # Additionally, if there are too many input params so that we will put them into a container class,
            # then there will be no need for separate case (2) either.
            input_fields_wo_excluded = None

        # Temporary hack, since Parse requires all the fields from ParseSetup: don't generate the required-fields-only
        # method
        if 'parse' == apiname:
            required_fields = None

        for fields in [
                required_fields, input_fields_wo_excluded, input_fields
        ]:
            if fields is None: continue
            use_schema_param = (len(fields) >= 4)
            value_field_strs = []
            typed_field_strs = []
            for field in fields:
                ftype = translate_type(field["type"], field["schema_name"])
                fname = translate_name(field["name"])
                typed_field_strs.append("%s %s" % (ftype, fname))
                if use_schema_param: fname = "params." + fname
                if ftype.endswith("KeyV3"):
                    s = "keyToString(%s)" % fname
                elif ftype.endswith("KeyV3[]"):
                    s = "keyArrayToStringArray(%s)" % fname
                elif ftype == "ColSpecifierV3":
                    s = "colToString(%s)" % fname
                else:
                    s = fname
                value_field_strs.append(s)

            if use_schema_param:
                args = route["input_schema"] + " params"
                values = "\n      " + ",\n      ".join(
                    value_field_strs) + "\n    "
            else:
                args = ", ".join(typed_field_strs)
                values = ", ".join(value_field_strs)
                if fields == input_fields_wo_excluded:
                    values += ", \"\""

            method = apiname if route["handler_method"] == "exec" else route[
                "handler_method"]
            yield "  public {type} {method}({args}) throws IOException {{".\
                  format(type=outtype, method=apiname, args=args)
            yield "    {clazz} s = getService({clazz}.class);".format(
                clazz=class_name)
            yield "    return s.{method}({values}).execute().body();".format(
                method=method, values=values)
            yield "  }"
        yield ""

    yield dedent(
        2, """

          //--------- PRIVATE --------------------------------------------------------------------------------------------------

          private Retrofit retrofit;
          private String _url = DEFAULT_URL;
          private int timeout_s = 60;
          private int pollInterval_ms = 1000;

          private void initializeRetrofit() {
            Gson gson = new GsonBuilder()
              .registerTypeAdapterFactory(new ModelV3TypeAdapter())
              .registerTypeAdapter(KeyV3.class, new KeySerializer())
              .registerTypeAdapter(ColSpecifierV3.class, new ColSerializer())
              .registerTypeAdapter(ModelBuilderSchema.class, new ModelDeserializer())
              .registerTypeAdapter(ModelSchemaBaseV3.class, new ModelSchemaDeserializer())
              .registerTypeAdapter(ModelOutputSchemaV3.class, new ModelOutputDeserializer())
              .registerTypeAdapter(ModelParametersSchemaV3.class, new ModelParametersDeserializer())
              .create();

            OkHttpClient client = new OkHttpClient.Builder()
              .connectTimeout(timeout_s, TimeUnit.SECONDS)
              .writeTimeout(timeout_s, TimeUnit.SECONDS)
              .readTimeout(timeout_s, TimeUnit.SECONDS)
              .build();

            this.retrofit = new Retrofit.Builder()
              .client(client)
              .baseUrl(_url)
              .addConverterFactory(GsonConverterFactory.create(gson))
              .build();
          }

          private Retrofit getRetrofit() {
            if (retrofit == null) initializeRetrofit();
            return retrofit;
          }

          private <T> T getService(Class<T> clazz) {
            return getRetrofit().create(clazz);
          }


          /**
           * Keys get sent as Strings and returned as objects also containing the type and URL,
           * so they need a custom GSON serializer.
           */
          private static class KeySerializer implements JsonSerializer<KeyV3>, JsonDeserializer<KeyV3> {
            @Override
            public JsonElement serialize(KeyV3 key, Type typeOfKey, JsonSerializationContext context) {
              return new JsonPrimitive(key.name);
            }
            @Override
            public KeyV3 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
              if (json.isJsonNull()) return null;
              JsonObject jobj = json.getAsJsonObject();
              String type = jobj.get(\"type\").getAsString();
              switch (type) {
                // TODO: dynamically generate all possible cases
                case \"Key<Model>\": return context.deserialize(jobj, ModelKeyV3.class);
                case \"Key<Job>\":   return context.deserialize(jobj, JobKeyV3.class);
                case \"Key<Grid>\":  return context.deserialize(jobj, GridKeyV3.class);
                case \"Key<Frame>\": return context.deserialize(jobj, FrameKeyV3.class);
                default: throw new JsonParseException(\"Unable to deserialize key of type \" + type);
              }
            }
          }

          private static class ColSerializer implements JsonSerializer<ColSpecifierV3> {
            @Override
            public JsonElement serialize(ColSpecifierV3 col, Type typeOfCol, JsonSerializationContext context) {
              return new JsonPrimitive(col.columnName);
            }
          }

        """)

    def inj(middle):
        return lambda schema, algo: schema[:len(algo)] + middle + schema[len(
            algo):]

    for clz, base, target_clz_factory in [
        ("ModelDeserializer", "ModelBuilderSchema",
         lambda schema, algo: schema),
        ("ModelSchemaDeserializer", "ModelSchemaBaseV3", inj("Model")),
        ("ModelOutputDeserializer", "ModelOutputSchemaV3", inj("ModelOutput")),
        ("ModelParametersDeserializer", "ModelParametersSchemaV3",
         inj("Parameters"))
    ]:
        yield "  /**"
        yield "   * Factory method for parsing a %s json object into an instance of the model-specific subclass." % base
        yield "   */"
        yield "  private static class %s implements JsonDeserializer<%s> {" % (
            clz, base)
        yield "    @Override"
        yield "    public %s deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)" % base
        yield "      throws JsonParseException {"
        yield "      if (json.isJsonNull()) return null;"
        yield "      if (json.isJsonObject()) {"
        yield "        JsonObject jobj = json.getAsJsonObject();"
        yield "        if (jobj.has(\"algo\")) {"
        yield "          String algo = jobj.get(\"algo\").getAsJsonPrimitive().getAsString().toLowerCase();"
        yield "          switch (algo) {"
        for route in endpoints:
            if route["class_name"] == "ModelBuilders" and route[
                    "api_name"].startswith("train"):
                algo = route["algo"]
                oschema = route["output_schema"]
                assert oschema.lower()[:len(
                    algo)] == algo, "Wrong output schema for algo %s: %s" % (
                        algo, oschema)
                model = target_clz_factory(oschema, algo)
                yield "            case \"{algo}\": return context.deserialize(json, {model}.class);".format(
                    **locals())
        yield "            default:"
        yield "              throw new JsonParseException(\"Unable to deserialize model of type \" + algo);"
        yield "          }"
        yield "        }"
        yield "      }"
        yield "      throw new JsonParseException(\"Invalid %s element \" + json.toString());" % base
        yield "    }"
        yield "  }"
        yield ""

    yield dedent(
        2, """
          private static class ModelV3TypeAdapter implements TypeAdapterFactory {
            @Override
            public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
              final Class<? super T> rawType = type.getRawType();
              if (!ModelBuilderSchema.class.isAssignableFrom(rawType) &&
                  !ModelSchemaBaseV3.class.isAssignableFrom(rawType)) return null;
              final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
              return new TypeAdapter<T>() {
                @Override
                public void write(JsonWriter out, T value) throws IOException {
                  delegate.write(out, value);
                }
                @Override
                public T read(JsonReader in) throws IOException {
                  JsonObject jobj = new JsonParser().parse(in).getAsJsonObject();
                  if (jobj.has(\"parameters\") && jobj.get(\"parameters\").isJsonArray()) {
                    JsonArray jarr = jobj.get(\"parameters\").getAsJsonArray();
                    JsonObject paramsNew = new JsonObject();
                    for (JsonElement item : jarr) {
                      JsonObject itemObj = item.getAsJsonObject();
                      paramsNew.add(itemObj.get(\"name\").getAsString(), itemObj.get(\"actual_value\"));
                    }
                    jobj.add(\"parameters\", paramsNew);
                  }
                  // noinspection unchecked
                  return (T) new Gson().fromJson(jobj, rawType);
                }
              };
            }
          }


          /**
           * Return an array of Strings for an array of keys.
           */
          public static String[] keyArrayToStringArray(KeyV3[] keys) {
            if (keys == null) return null;
            String[] ids = new String[keys.length];
            int i = 0;
            for (KeyV3 key : keys) ids[i++] = key.name;
            return ids;
          }

          /**
           * Return an array of keys from an array of Strings.
           * @param ids array of string ids to convert to KeyV3's
           * @param clz class of key objects to create. Since we have JobKeyV3, FrameKeyV3, ModelKeyV3, etc -- this
           *            method needs to know which of these keys you want to create
           */
          public static <T extends KeyV3> T[] stringArrayToKeyArray(String[] ids, Class<T> clz) {
            if (ids == null) return null;
            // noinspection unchecked
            T[] keys = (T[]) Array.newInstance(clz, ids.length);
            String keyType = clz.getSimpleName();
            if (keyType.endsWith(\"KeyV3\")) keyType = keyType.substring(0, keyType.length()-5);
            try {
              int i = 0;
              for (String id: ids) {
                keys[i] = clz.getConstructor().newInstance();
                keys[i].name = id;
                keys[i].type = keyType;
                i++;
              }
            }
            catch (Exception e) {
              e.printStackTrace();
            }
            return keys;
          }

          /**
           *
           */
          public static String keyToString(KeyV3 key) {
            return key == null? null : key.name;
          }

          /**
           *
           */
          public static FrameKeyV3 stringToFrameKey(String key) {
            if (key == null) return null;
            FrameKeyV3 k = new FrameKeyV3();
            k.name = key;
            return k;
          }

          /**
           *
           */
          private static String colToString(ColSpecifierV3 col) {
            return col == null? null : col.columnName;
          }

          /**
           *
           */
          public static String stringToCol(String col) {
            if (col == null) return null;
            ColSpecifierV3 c = new ColSpecifierV3();
            c.columnName = col;
            return col;
          }


          public static void copyFields(Object to, Object from) {
            Field[] fromFields = from.getClass().getDeclaredFields();
            Field[] toFields   = to.getClass().getDeclaredFields();

            for (Field fromField : fromFields){
              Field toField;
              try {
                toField = to.getClass().getDeclaredField(fromField.getName());
                fromField.setAccessible(true);
                toField.setAccessible(true);
                toField.set(to, fromField.get(from));
              }
              catch (Exception ignored) {
                // NoSuchField is the normal case
              }
            }
          }
        }
        """)
Example #19
0
def gen_module(schema, name):
    classname = algo_to_classname(name)
    extra_imports = extra_imports_for(name)
    help_preamble = help_preamble_for(name)
    help_epilogue = help_epilogue_for(name)
    init_extra = init_extra_for(name)
    class_extra = class_extra_for(name)
    module_extra = module_extra_for(name)

    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    yield "from .estimator_base import H2OEstimator"
    if extra_imports:
        yield reindent_block(extra_imports, 0) + ""
    yield ""
    yield ""
    yield "class %s(H2OEstimator):" % classname
    yield "    \"\"\""
    yield "    %s" % schema["algo_full_name"]
    yield "    %s" % ("-" * len(schema["algo_full_name"]))
    if help_preamble:
        yield "    %s" % reindent_block(help_preamble, 4)
    yield ""
    yield "    Parameters (optional, unless specified otherwise)"
    yield "    ----------"
    for param in schema["parameters"]:
        assert (param["type"] == "enum") == bool(param["values"]), "Values are expected for enum types only"
        ptype = translate_type(param["type"], param["values"])
        name = param["name"]
        if param["required"]: ptype += ", required"
        yield "      %s : %s" % (name, bi.wrap(ptype, " " * (9 + len(name)), indent_first=False))
        yield bi. wrap(param["help"], " " * 8)
        if param["default_value"] is not None:
            yield "        Default: %s" % stringify(param["default_value"])
        yield ""
    if help_epilogue:
        yield "    %s" % reindent_block(help_epilogue, 4)
    yield "    \"\"\""
    yield "    def __init__(self, **kwargs):"
    yield "        super(%s, self).__init__()" % classname
    yield "        self._parms = kwargs"
    if init_extra:
        yield "        %s" % reindent_block(init_extra, 8)
    yield ""
    for param in schema["parameters"]:
        name = param["name"]
        yield "    @property"
        yield "    def %s(self):" % name
        yield "        return self._parms[\"%s\"]" % name
        yield ""
        yield "    @%s.setter" % name
        yield "    def %s(self, value):" % name
        yield "        self._parms[\"%s\"] = value" % name
        yield ""
    if class_extra:
        yield "    %s" % reindent_block(class_extra, 4)
        yield ""
    if module_extra:
        yield "%s" % reindent_block(module_extra, 0)
        yield ""
Example #20
0
def generate_main_class(endpoints):
    yield "/**"
    yield " * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_java.py"
    yield " * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield " */"
    yield "package water.bindings;"
    yield ""
    yield "import water.bindings.pojos.*;"
    yield "import water.bindings.proxies.retrofit.*;"
    yield "import retrofit2.*;"
    yield "import retrofit2.converter.gson.GsonConverterFactory;"
    yield "import com.google.gson.*;"
    yield "import okhttp3.OkHttpClient;"
    yield "import java.io.IOException;"
    yield "import java.lang.reflect.Type;"
    yield "import java.util.concurrent.TimeUnit;"
    yield ""
    yield "public class H2oApi {"
    yield ""
    yield "  public H2oApi() {}"
    yield "  public H2oApi(String url) { this.url = url; }"
    yield ""
    yield "  public H2oApi setUrl(String s) {"
    yield "    url = s;"
    yield "    retrofit = null;"
    yield "    return this;"
    yield "  }"
    yield ""
    yield "  public H2oApi setTimeout(int t) {"
    yield "    timeout_s = t;"
    yield "    retrofit = null;"
    yield "    return this;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   * Set time interval for job polling in {@link #waitForJobCompletion(JobKeyV3)}."
    yield "   *   @param millis time interval, in milliseconds"
    yield "   */"
    yield "  public H2oApi setJobPollInterval(int millis) {"
    yield "    pollInterval_ms = millis;"
    yield "    return this;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   * Continuously poll server for the status of the given job, until it completes."
    yield "   *   @param jobKey job to query"
    yield "   *   @return the finished job"
    yield "   */"
    yield "  public JobV3 waitForJobCompletion(JobKeyV3 jobKey) {"
    yield "    return waitForJobCompletion(keyToString(jobKey));"
    yield "  }"
    yield "  public JobV3 waitForJobCompletion(String jobId) {"
    yield "    Jobs jobService = getService(Jobs.class);"
    yield "    Response<JobsV3> jobsResponse = null;"
    yield "    int retries = 3;"
    yield "    JobsV3 jobs = null;"
    yield "    do {"
    yield "      try {"
    yield "        Thread.sleep(pollInterval_ms);"
    yield "        jobsResponse = jobService.fetch(jobId).execute();"
    yield "      } catch (IOException e) {"
    yield "        System.err.println(\"Caught exception: \" + e);"
    yield "      } catch (InterruptedException e) { /* pass */ }"
    yield "      if (jobsResponse == null || !jobsResponse.isSuccessful())"
    yield "        if (retries-- > 0)"
    yield "          continue;"
    yield "        else"
    yield "          throw new RuntimeException(\"/3/Jobs/\" + jobId + \" failed 3 times.\");"
    yield "      jobs = jobsResponse.body();"
    yield "      if (jobs.jobs == null || jobs.jobs.length != 1)"
    yield "        throw new RuntimeException(\"Failed to find Job: \" + jobId);"
    yield "    } while (jobs != null && jobs.jobs[0].status.equals(\"RUNNING\"));"
    yield "    return jobs == null? null : jobs.jobs[0];"
    yield "  }"
    yield ""

    for route in endpoints:
        apiname = route["api_name"]
        class_name = route["class_name"]
        outtype = route["output_schema"]
        input_fields = route["input_params"]
        required_fields = [
            field for field in input_fields if field["required"]
        ]
        input_fields_wo_excluded = [
            field for field in input_fields
            if field["name"] != "_exclude_fields"
        ]

        yield "  /**"
        yield bi.wrap(route["summary"], indent="   * ")
        yield "   */"
        # Make several versions of each API call:
        #  (1) Only the required parameters
        #  (2) All parameters except the _excluded_fields
        #  (3) All parameters
        li = len(input_fields)
        le = len(input_fields_wo_excluded)
        lr = len(required_fields)
        assert lr <= 3, "Too many required fields in method " + apiName
        if lr == li:
            # The set of required fields is the same as the set of input fields. No need for (2) and (3).
            input_fields = None
            input_fields_wo_excluded = None
        elif le == li or le == lr or li >= 4:
            # If set (2) coincides with either (1) or (3), then we will not generate code for it.
            # Additionally, if there are too many input params so that we will put them into a container class,
            # then there will be no need for separate case (2) either.
            input_fields_wo_excluded = None

        for fields in [
                required_fields, input_fields_wo_excluded, input_fields
        ]:
            if fields is None: continue
            use_schema_param = (len(fields) >= 4)
            value_field_strs = []
            typed_field_strs = []
            for field in fields:
                ftype = translate_type(field["type"], field["schema_name"])
                fname = translate_name(field["name"])
                typed_field_strs.append("%s %s" % (ftype, fname))
                if use_schema_param: fname = "params." + fname
                if ftype.endswith("KeyV3"):
                    s = "keyToString(%s)" % fname
                elif ftype.endswith("KeyV3[]"):
                    s = "keyArrayToStringArray(%s)" % fname
                elif ftype.startswith("ColSpecifier"):
                    s = "colToString(%s)" % fname
                else:
                    s = fname
                value_field_strs.append(s)

            if use_schema_param:
                args = route["input_schema"] + " params"
                values = "\n      " + ",\n      ".join(
                    value_field_strs) + "\n    "
            else:
                args = ", ".join(typed_field_strs)
                values = ", ".join(value_field_strs)
                if fields == input_fields_wo_excluded:
                    values += ", \"\""

            yield "  public {type} {method}({args}) throws IOException {{".\
                  format(type=outtype, method=apiname, args=args)
            yield "    {clazz} s = getService({clazz}.class);".format(
                clazz=class_name)
            yield "    return s.{method}({values}).execute().body();".\
                  format(method=route["handler_method"], values=values)
            yield "  }"
        yield ""

    yield ""
    yield "  //--------- PRIVATE " + "-" * 98
    yield ""
    yield "  private Retrofit retrofit;"
    yield "  private String url = \"http://localhost/54321/\";"
    yield "  private int timeout_s = 60;"
    yield "  private int pollInterval_ms = 1000;"
    yield ""
    yield "  private void initializeRetrofit() {"
    yield "    Gson gson = new GsonBuilder()"
    yield "      .registerTypeAdapter(KeyV3.class, new KeySerializer())"
    yield "      .registerTypeAdapter(ColSpecifierV3.class, new ColSerializer())"
    yield "      .registerTypeAdapter(ModelsV3.class, new ModelDeserializer())"
    yield "      .create();"
    yield ""
    yield "    OkHttpClient client = new OkHttpClient.Builder()"
    yield "      .connectTimeout(timeout_s, TimeUnit.SECONDS)"
    yield "      .writeTimeout(timeout_s, TimeUnit.SECONDS)"
    yield "      .readTimeout(timeout_s, TimeUnit.SECONDS)"
    yield "      .build();"
    yield ""
    yield "    this.retrofit = new Retrofit.Builder()"
    yield "      .client(client)"
    yield "      .baseUrl(url)"
    yield "      .addConverterFactory(GsonConverterFactory.create(gson))"
    yield "      .build();"
    yield "  }"
    yield ""
    yield "  private Retrofit getRetrofit() {"
    yield "    if (retrofit == null) initializeRetrofit();"
    yield "    return retrofit;"
    yield "  }"
    yield ""
    yield "  private <T> T getService(Class<T> clazz) {"
    yield "    return getRetrofit().create(clazz);"
    yield "  }"
    yield ""
    yield ""
    yield "  /**"
    yield "   * Keys get sent as Strings and returned as objects also containing the type and URL,"
    yield "   * so they need a custom GSON serializer."
    yield "   */"
    yield "  private static class KeySerializer implements JsonSerializer<KeyV3> {"
    yield "    @Override"
    yield "    public JsonElement serialize(KeyV3 key, Type typeOfKey, JsonSerializationContext context) {"
    yield "      return new JsonPrimitive(key.name);"
    yield "    }"
    yield "  }"
    yield "  private static class ColSerializer implements JsonSerializer<ColSpecifierV3> {"
    yield "    @Override"
    yield "    public JsonElement serialize(ColSpecifierV3 col, Type typeOfCol, JsonSerializationContext context) {"
    yield "      return new JsonPrimitive(col.columnName);"
    yield "    }"
    yield "  }"
    yield "  /**"
    yield "   * Factory method for parsing a ModelsV3 json object into an instance of the model-specific subclass."
    yield "   */"
    yield "  private static class ModelDeserializer implements JsonDeserializer<ModelsV3> {"
    yield "    @Override"
    yield "    public ModelsV3 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)"
    yield "      throws JsonParseException {"
    yield "      if (json.isJsonNull()) return null;"
    yield "      if (json.isJsonObject()) {"
    yield "        JsonObject jobj = json.getAsJsonObject();"
    yield "        if (jobj.has(\"algo\")) {"
    yield "          String algo = jobj.get(\"algo\").getAsJsonPrimitive().getAsString().toLowerCase();"
    yield "          switch (algo) {"
    for route in endpoints:
        if route["class_name"] == "ModelBuilders" and route[
                "api_name"].startswith("train"):
            algo = route["algo"]
            oschema = route["output_schema"]
            assert oschema.lower(
            )[:len(algo)] == algo, "Wrong output schema for algo %s: %s" % (
                algo, oschema)
            model = oschema[:len(algo)] + "Model" + oschema[len(
                algo):]  # "DeepLearningV3" => "DeepLearningModelV3"
            yield "            case \"{algo}\": return context.deserialize(json, {model}.class);".format(
                **locals())
    yield "            default:"
    yield "              throw new JsonParseException(\"Unable to deserialize model of type \" + algo);"
    yield "          }"
    yield "        }"
    yield "      }"
    yield "      throw new JsonParseException(\"Invalid ModelsV3 element \" + json.toString());"
    yield "    }"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   * Return an array of Strings for an array of keys."
    yield "   */"
    yield "  private static String[] keyArrayToStringArray(KeyV3[] keys) {"
    yield "    if (keys == null) return null;"
    yield "    String[] ids = new String[keys.length];"
    yield "    int i = 0;"
    yield "    for (KeyV3 key : keys) ids[i++] = key.name;"
    yield "    return ids;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   *"
    yield "   */"
    yield "  private static String keyToString(KeyV3 key) {"
    yield "    return key == null? null : key.name;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   *"
    yield "   */"
    yield "  private static String colToString(ColSpecifierV3 col) {"
    yield "    return col == null? null : col.columnName;"
    yield "  }"
    yield ""
    yield "}"
Example #21
0
def gen_module(schema, algo):
    help_preamble = help_preamble_for(algo)
    help_epilogue = help_epilogue_for(algo)
    help_afterword = help_afterword_for(algo)
    model_name = algo_to_modelname(algo)
    help_example = help_example_for(algo)
    help_return = help_return_for(algo)
    help_references = help_references_for(algo)
    class_extra = class_extra_for(algo)

    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_R.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details) \n#'"
    yield "# -------------------------- %s -------------------------- #" % model_name
    if help_preamble:
        lines = help_preamble.split("\n")
        for line in lines:
            yield "#' %s" % line.lstrip()
    yield "#'"
    yield "#' @param x A vector containing the \code{character} names of the predictors in the model."
    yield "#'        If x is missing,then all columns except y are used."
    yield "#' @param y The name of the response variable in the model."
    for param in schema["parameters"]:
        if param["name"] == "ignored_columns" or param[
                "name"] == "response_column":
            continue
        phelp = param["help"]
        if param["type"] == "boolean":
            phelp = "\code{Logical}. " + phelp
        if param["values"]:
            phelp += " Must be one of: %s." % ", ".join(
                '"%s"' % p for p in param["values"])
        if param["default_value"] is not None:
            phelp += " Defaults to %s." % param["default_value"]
        yield "#' @param %s %s" % (
            param["name"],
            bi.wrap(phelp, indent=("#'        "), indent_first=False))
    if help_return:
        yield "#' @return %s" % bi.wrap(
            help_return, indent=("#'          "), indent_first=False)
    if help_epilogue:
        yield "#' @seealso %s" % bi.wrap(
            help_epilogue, indent=("#'          "), indent_first=False)
    if help_references:
        #lines = help_references.split("\n")
        #for line in lines:
        #    yield "#' %s" % line.lstrip()
        yield "#' @references %s" % bi.wrap(
            help_references, indent=("#'             "), indent_first=False)
    if help_example:
        yield "#' @examples"
        lines = help_example.split("\n")
        for line in lines:
            yield "#' %s" % line.lstrip()
    yield "#' @export"
    yield "h2o.%s <- function(x, y, " % algo
    list = []
    for param in schema["parameters"]:
        if param["name"] == "ignored_columns" or param[
                "name"] == "response_column":
            continue
        if param["type"][:4] == "enum" or param["default_value"] is not None:
            list.append(
                indent("%s  = %s" % (param["name"], normalize_value(param)),
                       17 + len(algo)))
        else:
            list.append(indent(param["name"], 17 + len(algo)))
    yield ", \n".join(list)
    yield indent(") \n{", 17 + len(algo))
    yield "  #If x is missing, then assume user wants to use all columns as features."
    yield "  if(missing(x)){"
    yield "     if(is.numeric(y)){"
    yield "         x <- setdiff(col(training_frame),y)"
    yield "     }else{"
    yield "         x <- setdiff(colnames(training_frame),y)"
    yield "     }"
    yield "  }"
    yield ""
    yield "  # Required args: training_frame"
    yield "  if( missing(training_frame) ) stop(\"argument \'training_frame\' is missing, with no default\")"
    yield "  if( missing(validation_frame) ) validation_frame = NULL"
    yield "  # Training_frame and validation_frame may be a key or an H2OFrame object"
    yield "  if (!is.H2OFrame(training_frame))"
    yield "     tryCatch(training_frame <- h2o.getFrame(training_frame),"
    yield "           error = function(err) {"
    yield "             stop(\"argument \'training_frame\' must be a valid H2OFrame or key\")"
    yield "           })"
    yield "  if (!is.null(validation_frame)) {"
    yield "     if (!is.H2OFrame(validation_frame))"
    yield "         tryCatch(validation_frame <- h2o.getFrame(validation_frame),"
    yield "             error = function(err) {"
    yield "                 stop(\"argument \'validation_frame\' must be a valid H2OFrame or key\")"
    yield "             })"
    yield "  }"
    yield "  # Parameter list to send to model builder"
    yield "  parms <- list()"
    yield "  parms$training_frame <- training_frame"
    yield "  args <- .verify_dataxy(training_frame, x, y, autoencoder)"
    yield "  if( !missing(offset_column) && !is.null(offset_column))  args$x_ignore <- args$x_ignore[!( offset_column == args$x_ignore )]"
    yield "  if( !missing(weights_column) && !is.null(weights_column)) args$x_ignore <- args$x_ignore[!( weights_column == args$x_ignore )]"
    yield "  if( !missing(fold_column) && !is.null(fold_column)) args$x_ignore <- args$x_ignore[!( fold_column == args$x_ignore )]"
    yield "  parms$response_column <- args$y"
    yield "  parms$ignored_columns <- args$x_ignore \n "

    for param in schema["parameters"]:
        if param["name"] == "ignored_columns" or param[
                "name"] == "response_column" or param[
                    "name"] == "training_frame":
            continue
        if param["name"] == "loss":
            yield "  if(!missing(loss)) {"
            yield "    if(loss == \"MeanSquare\") {"
            yield "      warning(\"Loss name 'MeanSquare' is deprecated; please use 'Quadratic' instead.\")"
            yield "      parms$loss <- \"Quadratic\""
            yield "    } else "
            yield "      parms$loss <- loss"
            yield "  }"
        yield "  if (!missing(%s))" % param["name"]
        yield "    parms$%s <- %s" % (param["name"], param["name"])
    yield "  .h2o.modelJob('%s', parms, h2oRestApiVersion=3) \n}" % algo

    if help_afterword:
        lines = help_afterword.split("\n")
        for line in lines:
            yield "%s" % line.lstrip()
        #yield "%s" % bi.wrap(help_afterword, indent=("#' "), indent_first=True)

    if class_extra:
        yield class_extra
Example #22
0
def generate_main_class(endpoints):
    yield \
"""
/**
 * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_java.py
 * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)
 */
package water.bindings;

import water.bindings.pojos.*;
import water.bindings.proxies.retrofit.*;
import retrofit2.*;
import retrofit2.converter.gson.GsonConverterFactory;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import okhttp3.OkHttpClient;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;
import java.lang.reflect.Field;

public class H2oApi {

  public static String DEFAULT_URL = \"http://localhost:54321/\";

  public H2oApi() {
      this(DEFAULT_URL);
  }
  public H2oApi(String url) { this.url = url; }

  public H2oApi setUrl(String s) {
    url = s;
    retrofit = null;
    return this;
  }

  public H2oApi setTimeout(int t) {
    timeout_s = t;
    retrofit = null;
    return this;
  }

  /**
   * Set time interval for job polling in {@link #waitForJobCompletion(JobKeyV3)}.
   *   @param millis time interval, in milliseconds
   */
  public H2oApi setJobPollInterval(int millis) {
    pollInterval_ms = millis;
    return this;
  }

  /**
   * Continuously poll server for the status of the given job, until it completes.
   *   @param jobKey job to query
   *   @return the finished job
   */
  public JobV3 waitForJobCompletion(JobKeyV3 jobKey) {
    return waitForJobCompletion(keyToString(jobKey));
  }
  public JobV3 waitForJobCompletion(String jobId) {
    Jobs jobService = getService(Jobs.class);
    Response<JobsV3> jobsResponse = null;
    int retries = 3;
    JobsV3 jobs = null;
    do {
      try {
        Thread.sleep(pollInterval_ms);
        jobsResponse = jobService.fetch(jobId).execute();
      } catch (IOException e) {
        System.err.println(\"Caught exception: \" + e);
      } catch (InterruptedException e) { /* pass */ }
      if (jobsResponse == null || !jobsResponse.isSuccessful())
        if (retries-- > 0)
          continue;
        else
          throw new RuntimeException(\"/3/Jobs/\" + jobId + \" failed 3 times.\");
      jobs = jobsResponse.body();
      if (jobs.jobs == null || jobs.jobs.length != 1)
        throw new RuntimeException(\"Failed to find Job: \" + jobId);
    } while (jobs != null && jobs.jobs[0].status.equals(\"RUNNING\"));
    return jobs == null? null : jobs.jobs[0];
  }

"""

    for route in endpoints:
        apiname = route["api_name"]
        class_name = route["class_name"]
        outtype = route["output_schema"]
        input_fields = route["input_params"]
        required_fields = [
            field for field in input_fields if field["required"]
        ]
        input_fields_wo_excluded = [
            field for field in input_fields
            if field["name"] != "_exclude_fields"
        ]

        yield "  /**"
        yield bi.wrap(route["summary"], indent="   * ")
        yield "   */"
        # Make several versions of each API call:
        #  (1) Only the required parameters
        #  (2) All parameters except the _excluded_fields
        #  (3) All parameters
        li = len(input_fields)
        le = len(input_fields_wo_excluded)
        lr = len(required_fields)
        assert lr <= 3, "Too many required fields in method " + apiname
        if lr == li:
            # The set of required fields is the same as the set of input fields. No need for (2) and (3).
            input_fields = None
            input_fields_wo_excluded = None
        elif le == li or le == lr or li >= 4:
            # If set (2) coincides with either (1) or (3), then we will not generate code for it.
            # Additionally, if there are too many input params so that we will put them into a container class,
            # then there will be no need for separate case (2) either.
            input_fields_wo_excluded = None

        # Temporary hack, since Parse reuires all the fields from ParseSetup: don't generate the required-fields-only method
        if 'parse' == apiname:
            required_fields = None

        for fields in [
                required_fields, input_fields_wo_excluded, input_fields
        ]:
            if fields is None: continue
            use_schema_param = (len(fields) >= 4)
            value_field_strs = []
            typed_field_strs = []
            for field in fields:
                ftype = translate_type(field["type"], field["schema_name"])
                fname = translate_name(field["name"])
                typed_field_strs.append("%s %s" % (ftype, fname))
                if use_schema_param: fname = "params." + fname
                if ftype.endswith("KeyV3"):
                    s = "keyToString(%s)" % fname
                elif ftype.endswith("KeyV3[]"):
                    s = "keyArrayToStringArray(%s)" % fname
                elif ftype.startswith("ColSpecifier"):
                    s = "colToString(%s)" % fname
                else:
                    s = fname
                value_field_strs.append(s)

            if use_schema_param:
                args = route["input_schema"] + " params"
                values = "\n      " + ",\n      ".join(
                    value_field_strs) + "\n    "
            else:
                args = ", ".join(typed_field_strs)
                values = ", ".join(value_field_strs)
                if fields == input_fields_wo_excluded:
                    values += ", \"\""

            yield "  public {type} {method}({args}) throws IOException {{".\
                  format(type=outtype, method=apiname, args=args)
            yield "    {clazz} s = getService({clazz}.class);".format(
                clazz=class_name)
            yield "    return s.{method}({values}).execute().body();".\
                  format(method=route["handler_method"], values=values)
            yield "  }"
        yield ""

    yield \
"""

  //--------- PRIVATE " + ("-" * 98)

  private Retrofit retrofit;
  private String url = DEFAULT_URL;
  private int timeout_s = 60;
  private int pollInterval_ms = 1000;

  private void initializeRetrofit() {
    Gson gson = new GsonBuilder()
      .registerTypeAdapterFactory(new ModelV3TypeAdapter())
      .registerTypeAdapter(KeyV3.class, new KeySerializer())
      .registerTypeAdapter(ColSpecifierV3.class, new ColSerializer())
      .registerTypeAdapter(ModelBuilderSchema.class, new ModelDeserializer())
      .registerTypeAdapter(ModelSchemaBaseV3.class, new ModelSchemaDeserializer())
      .create();

    OkHttpClient client = new OkHttpClient.Builder()
      .connectTimeout(timeout_s, TimeUnit.SECONDS)
      .writeTimeout(timeout_s, TimeUnit.SECONDS)
      .readTimeout(timeout_s, TimeUnit.SECONDS)
      .build();

    this.retrofit = new Retrofit.Builder()
      .client(client)
      .baseUrl(url)
      .addConverterFactory(GsonConverterFactory.create(gson))
      .build();
  }

  private Retrofit getRetrofit() {
    if (retrofit == null) initializeRetrofit();
    return retrofit;
  }

  private <T> T getService(Class<T> clazz) {
    return getRetrofit().create(clazz);
  }


  /**
   * Keys get sent as Strings and returned as objects also containing the type and URL,
   * so they need a custom GSON serializer.
   */
  private static class KeySerializer implements JsonSerializer<KeyV3>, JsonDeserializer<KeyV3> {
    @Override
    public JsonElement serialize(KeyV3 key, Type typeOfKey, JsonSerializationContext context) {
      return new JsonPrimitive(key.name);
    }
    @Override
    public KeyV3 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
      if (json.isJsonNull()) return null;
      JsonObject jobj = json.getAsJsonObject();
      String type = jobj.get(\"type\").getAsString();
      switch (type) {
        // TODO: dynamically generate all possible cases
        case \"Key<Model>\": return context.deserialize(jobj, ModelKeyV3.class);
        case \"Key<Job>\":   return context.deserialize(jobj, JobKeyV3.class);
        case \"Key<Grid>\":  return context.deserialize(jobj, GridKeyV3.class);
        case \"Key<Frame>\": return context.deserialize(jobj, FrameKeyV3.class);
        default: throw new JsonParseException(\"Unable to deserialize key of type \" + type);
      }
    }
  }

  private static class ColSerializer implements JsonSerializer<ColSpecifierV3> {
    @Override
    public JsonElement serialize(ColSpecifierV3 col, Type typeOfCol, JsonSerializationContext context) {
      return new JsonPrimitive(col.columnName);
    }
  }

"""

    for clz, base, target_clz_factory in [
        ("ModelDeserializer", "ModelBuilderSchema",
         lambda schema, algo: schema),
        ("ModelSchemaDeserializer", "ModelSchemaBaseV3",
         lambda schema, algo: schema[:len(algo)] + "Model" + schema[len(algo):]
         )
    ]:
        yield "  /**"
        yield "   * Factory method for parsing a %s json object into an instance of the model-specific subclass." % base
        yield "   */"
        yield "  private static class %s implements JsonDeserializer<%s> {" % (
            clz, base)
        yield "    @Override"
        yield "    public %s deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)" % base
        yield "      throws JsonParseException {"
        yield "      if (json.isJsonNull()) return null;"
        yield "      if (json.isJsonObject()) {"
        yield "        JsonObject jobj = json.getAsJsonObject();"
        yield "        if (jobj.has(\"algo\")) {"
        yield "          String algo = jobj.get(\"algo\").getAsJsonPrimitive().getAsString().toLowerCase();"
        yield "          switch (algo) {"
        for route in endpoints:
            if route["class_name"] == "ModelBuilders" and route[
                    "api_name"].startswith("train"):
                algo = route["algo"]
                oschema = route["output_schema"]
                assert oschema.lower()[:len(
                    algo)] == algo, "Wrong output schema for algo %s: %s" % (
                        algo, oschema)
                model = target_clz_factory(oschema, algo)
                yield "            case \"{algo}\": return context.deserialize(json, {model}.class);".format(
                    **locals())
        yield "            default:"
        yield "              throw new JsonParseException(\"Unable to deserialize model of type \" + algo);"
        yield "          }"
        yield "        }"
        yield "      }"
        yield "      throw new JsonParseException(\"Invalid %s element \" + json.toString());" % base
        yield "    }"
        yield "  }"
        yield ""


    yield \
"""
Example #23
0
def generate_main_class(endpoints):
    yield dedent(0, """
        /*
         * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_java.py
         * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)
         */
        package water.bindings;

        import water.bindings.pojos.*;
        import water.bindings.proxies.retrofit.*;
        import retrofit2.*;
        import retrofit2.converter.gson.GsonConverterFactory;
        import com.google.gson.*;
        import com.google.gson.reflect.TypeToken;
        import com.google.gson.stream.JsonReader;
        import com.google.gson.stream.JsonWriter;
        import okhttp3.OkHttpClient;
        import java.io.IOException;
        import java.util.concurrent.TimeUnit;
        import java.lang.reflect.Array;
        import java.lang.reflect.Field;
        import java.lang.reflect.InvocationTargetException;
        import java.lang.reflect.Type;


        @SuppressWarnings("unused")
        public class H2oApi {

          public static String DEFAULT_URL = \"http://localhost:54321/\";

          public H2oApi() {
            this(DEFAULT_URL);
          }
          public H2oApi(String url) {
            _url = url;
          }

          public H2oApi setUrl(String url) {
            _url = url;
            retrofit = null;
            return this;
          }

          public H2oApi setTimeout(int t) {
            timeout_s = t;
            retrofit = null;
            return this;
          }

          /**
           * Set time interval for job polling in {@link #waitForJobCompletion(JobKeyV3)}.
           *   @param millis time interval, in milliseconds
           */
          public H2oApi setJobPollInterval(int millis) {
            pollInterval_ms = millis;
            return this;
          }

          /**
           * Continuously poll server for the status of the given job, until it completes.
           *   @param jobKey job to query
           *   @return the finished job
           */
          public JobV3 waitForJobCompletion(JobKeyV3 jobKey) {
            return waitForJobCompletion(keyToString(jobKey));
          }
          public JobV3 waitForJobCompletion(String jobId) {
            Jobs jobService = getService(Jobs.class);
            Response<JobsV3> jobsResponse = null;
            int retries = 3;
            JobsV3 jobs = null;
            do {
              try {
                Thread.sleep(pollInterval_ms);
                jobsResponse = jobService.fetch(jobId).execute();
              } catch (IOException e) {
                System.err.println(\"Caught exception: \" + e);
              } catch (InterruptedException e) { /* pass */ }
              if (jobsResponse == null || !jobsResponse.isSuccessful())
                if (retries-- > 0)
                  continue;
                else
                  throw new RuntimeException(\"/3/Jobs/\" + jobId + \" failed 3 times.\");
              jobs = jobsResponse.body();
              if (jobs.jobs == null || jobs.jobs.length != 1)
                throw new RuntimeException(\"Failed to find Job: \" + jobId);
            } while (jobs != null && jobs.jobs[0].status.equals(\"RUNNING\"));
            return jobs == null? null : jobs.jobs[0];
          }

        """)

    for route in endpoints:
        apiname = route["api_name"]
        class_name = route["class_name"]
        outtype = route["output_schema"]
        input_fields = route["input_params"]
        required_fields = [field for field in input_fields if field["required"]]
        input_fields_wo_excluded = [field for field in input_fields if field["name"] != "_exclude_fields"]

        yield "  /**"
        yield bi.wrap(route["summary"], indent="   * ")
        yield "   */"
        # Make several versions of each API call:
        #  (1) Only the required parameters
        #  (2) All parameters except the _excluded_fields
        #  (3) All parameters
        li = len(input_fields)
        le = len(input_fields_wo_excluded)
        lr = len(required_fields)
        assert lr <= 3, "Too many required fields in method " + apiname
        if lr == li:
            # The set of required fields is the same as the set of input fields. No need for (2) and (3).
            input_fields = None
            input_fields_wo_excluded = None
        elif le == li or le == lr or li >= 4:
            # If set (2) coincides with either (1) or (3), then we will not generate code for it.
            # Additionally, if there are too many input params so that we will put them into a container class,
            # then there will be no need for separate case (2) either.
            input_fields_wo_excluded = None

        # Temporary hack, since Parse requires all the fields from ParseSetup: don't generate the required-fields-only
        # method
        if 'parse' == apiname:
            required_fields = None

        for fields in [required_fields, input_fields_wo_excluded, input_fields]:
            if fields is None: continue
            use_schema_param = (len(fields) >= 4)
            value_field_strs = []
            typed_field_strs = []
            for field in fields:
                ftype = translate_type(field["type"], field["schema_name"])
                fname = translate_name(field["name"])
                typed_field_strs.append("%s %s" % (ftype, fname))
                if use_schema_param: fname = "params." + fname
                if ftype.endswith("KeyV3"):
                    s = "keyToString(%s)" % fname
                elif ftype.endswith("KeyV3[]"):
                    s = "keyArrayToStringArray(%s)" % fname
                elif ftype.startswith("ColSpecifier"):
                    s = "colToString(%s)" % fname
                else:
                    s = fname
                value_field_strs.append(s)

            if use_schema_param:
                args = route["input_schema"] + " params"
                values = "\n      " + ",\n      ".join(value_field_strs) + "\n    "
            else:
                args = ", ".join(typed_field_strs)
                values = ", ".join(value_field_strs)
                if fields == input_fields_wo_excluded:
                    values += ", \"\""

            yield "  public {type} {method}({args}) throws IOException {{".\
                  format(type=outtype, method=apiname, args=args)
            yield "    {clazz} s = getService({clazz}.class);".format(clazz=class_name)
            yield "    return s.{method}({values}).execute().body();".\
                  format(method=route["handler_method"], values=values)
            yield "  }"
        yield ""

    yield dedent(2, """

          //--------- PRIVATE --------------------------------------------------------------------------------------------------

          private Retrofit retrofit;
          private String _url = DEFAULT_URL;
          private int timeout_s = 60;
          private int pollInterval_ms = 1000;

          private void initializeRetrofit() {
            Gson gson = new GsonBuilder()
              .registerTypeAdapterFactory(new ModelV3TypeAdapter())
              .registerTypeAdapter(KeyV3.class, new KeySerializer())
              .registerTypeAdapter(ColSpecifierV3.class, new ColSerializer())
              .registerTypeAdapter(ModelBuilderSchema.class, new ModelDeserializer())
              .registerTypeAdapter(ModelSchemaBaseV3.class, new ModelSchemaDeserializer())
              .registerTypeAdapter(ModelOutputSchemaV3.class, new ModelOutputDeserializer())
              .registerTypeAdapter(ModelParametersSchemaV3.class, new ModelParametersDeserializer())
              .create();

            OkHttpClient client = new OkHttpClient.Builder()
              .connectTimeout(timeout_s, TimeUnit.SECONDS)
              .writeTimeout(timeout_s, TimeUnit.SECONDS)
              .readTimeout(timeout_s, TimeUnit.SECONDS)
              .build();

            this.retrofit = new Retrofit.Builder()
              .client(client)
              .baseUrl(_url)
              .addConverterFactory(GsonConverterFactory.create(gson))
              .build();
          }

          private Retrofit getRetrofit() {
            if (retrofit == null) initializeRetrofit();
            return retrofit;
          }

          private <T> T getService(Class<T> clazz) {
            return getRetrofit().create(clazz);
          }


          /**
           * Keys get sent as Strings and returned as objects also containing the type and URL,
           * so they need a custom GSON serializer.
           */
          private static class KeySerializer implements JsonSerializer<KeyV3>, JsonDeserializer<KeyV3> {
            @Override
            public JsonElement serialize(KeyV3 key, Type typeOfKey, JsonSerializationContext context) {
              return new JsonPrimitive(key.name);
            }
            @Override
            public KeyV3 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
              if (json.isJsonNull()) return null;
              JsonObject jobj = json.getAsJsonObject();
              String type = jobj.get(\"type\").getAsString();
              switch (type) {
                // TODO: dynamically generate all possible cases
                case \"Key<Model>\": return context.deserialize(jobj, ModelKeyV3.class);
                case \"Key<Job>\":   return context.deserialize(jobj, JobKeyV3.class);
                case \"Key<Grid>\":  return context.deserialize(jobj, GridKeyV3.class);
                case \"Key<Frame>\": return context.deserialize(jobj, FrameKeyV3.class);
                default: throw new JsonParseException(\"Unable to deserialize key of type \" + type);
              }
            }
          }

          private static class ColSerializer implements JsonSerializer<ColSpecifierV3> {
            @Override
            public JsonElement serialize(ColSpecifierV3 col, Type typeOfCol, JsonSerializationContext context) {
              return new JsonPrimitive(col.columnName);
            }
          }

        """)

    def inj(middle):
        return lambda schema, algo: schema[:len(algo)] + middle + schema[len(algo):]

    for clz, base, target_clz_factory in [
            ("ModelDeserializer", "ModelBuilderSchema", lambda schema, algo: schema),
            ("ModelSchemaDeserializer", "ModelSchemaBaseV3", inj("Model")),
            ("ModelOutputDeserializer", "ModelOutputSchemaV3", inj("ModelOutput")),
            ("ModelParametersDeserializer", "ModelParametersSchemaV3", inj("Parameters"))]:
        yield "  /**"
        yield "   * Factory method for parsing a %s json object into an instance of the model-specific subclass." % base
        yield "   */"
        yield "  private static class %s implements JsonDeserializer<%s> {" % (clz, base)
        yield "    @Override"
        yield "    public %s deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)" % base
        yield "      throws JsonParseException {"
        yield "      if (json.isJsonNull()) return null;"
        yield "      if (json.isJsonObject()) {"
        yield "        JsonObject jobj = json.getAsJsonObject();"
        yield "        if (jobj.has(\"algo\")) {"
        yield "          String algo = jobj.get(\"algo\").getAsJsonPrimitive().getAsString().toLowerCase();"
        yield "          switch (algo) {"
        for route in endpoints:
            if route["class_name"] == "ModelBuilders" and route["api_name"].startswith("train"):
                algo = route["algo"]
                oschema = route["output_schema"]
                assert oschema.lower()[:len(algo)] == algo, "Wrong output schema for algo %s: %s" % (algo, oschema)
                model = target_clz_factory(oschema, algo)
                yield "            case \"{algo}\": return context.deserialize(json, {model}.class);".format(**locals())
        yield "            default:"
        yield "              throw new JsonParseException(\"Unable to deserialize model of type \" + algo);"
        yield "          }"
        yield "        }"
        yield "      }"
        yield "      throw new JsonParseException(\"Invalid %s element \" + json.toString());" % base
        yield "    }"
        yield "  }"
        yield ""


    yield dedent(2, """
          private static class ModelV3TypeAdapter implements TypeAdapterFactory {
            @Override
            public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
              final Class<? super T> rawType = type.getRawType();
              if (!ModelBuilderSchema.class.isAssignableFrom(rawType) &&
                  !ModelSchemaBaseV3.class.isAssignableFrom(rawType)) return null;
              final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
              return new TypeAdapter<T>() {
                @Override
                public void write(JsonWriter out, T value) throws IOException {
                  delegate.write(out, value);
                }
                @Override
                public T read(JsonReader in) throws IOException {
                  JsonObject jobj = new JsonParser().parse(in).getAsJsonObject();
                  if (jobj.has(\"parameters\") && jobj.get(\"parameters\").isJsonArray()) {
                    JsonArray jarr = jobj.get(\"parameters\").getAsJsonArray();
                    JsonObject paramsNew = new JsonObject();
                    for (JsonElement item : jarr) {
                      JsonObject itemObj = item.getAsJsonObject();
                      paramsNew.add(itemObj.get(\"name\").getAsString(), itemObj.get(\"actual_value\"));
                    }
                    jobj.add(\"parameters\", paramsNew);
                  }
                  // noinspection unchecked
                  return (T) new Gson().fromJson(jobj, rawType);
                }
              };
            }
          }


          /**
           * Return an array of Strings for an array of keys.
           */
          public static String[] keyArrayToStringArray(KeyV3[] keys) {
            if (keys == null) return null;
            String[] ids = new String[keys.length];
            int i = 0;
            for (KeyV3 key : keys) ids[i++] = key.name;
            return ids;
          }

          /**
           * Return an array of keys from an array of Strings.
           * @param ids array of string ids to convert to KeyV3's
           * @param clz class of key objects to create. Since we have JobKeyV3, FrameKeyV3, ModelKeyV3, etc -- this
           *            method needs to know which of these keys you want to create
           */
          public static <T extends KeyV3> T[] stringArrayToKeyArray(String[] ids, Class<T> clz) {
            if (ids == null) return null;
            // noinspection unchecked
            T[] keys = (T[]) Array.newInstance(clz, ids.length);
            String keyType = clz.getSimpleName();
            if (keyType.endsWith(\"KeyV3\")) keyType = keyType.substring(0, keyType.length()-5);
            try {
              int i = 0;
              for (String id: ids) {
                keys[i] = clz.getConstructor().newInstance();
                keys[i].name = id;
                keys[i].type = keyType;
                i++;
              }
            }
            catch (Exception e) {
              e.printStackTrace();
            }
            return keys;
          }

          /**
           *
           */
          public static String keyToString(KeyV3 key) {
            return key == null? null : key.name;
          }

          /**
           *
           */
          public static FrameKeyV3 stringToFrameKey(String key) {
            if (key == null) return null;
            FrameKeyV3 k = new FrameKeyV3();
            k.name = key;
            return k;
          }

          /**
           *
           */
          private static String colToString(ColSpecifierV3 col) {
            return col == null? null : col.columnName;
          }

          /**
           *
           */
          public static String stringToCol(String col) {
            if (col == null) return null;
            ColSpecifierV3 c = new ColSpecifierV3();
            c.columnName = col;
            return col;
          }


          public static void copyFields(Object to, Object from) {
            Field[] fromFields = from.getClass().getDeclaredFields();
            Field[] toFields   = to.getClass().getDeclaredFields();

            for (Field fromField : fromFields){
              Field toField;
              try {
                toField = to.getClass().getDeclaredField(fromField.getName());
                fromField.setAccessible(true);
                toField.setAccessible(true);
                toField.set(to, fromField.get(from));
              }
              catch (Exception ignored) {
                // NoSuchField is the normal case
              }
            }
          }
        }
        """)
Example #24
0
def gen_module(schema, algo):
    """
    Ideally we should be able to avoid logic specific to algos in this file.
    Instead, customizations are externalized in ./python/gen_{algo}.py files.
    Logic that is specific to python types (e.g. H2OFrame, enums as list...) should however stay here
    as the type translation is done in this file.
    """
    classname = algo_to_classname(algo)
    extra_imports = get_customizations_for(algo, 'extensions.__imports__')
    class_doc = get_customizations_for(algo, 'doc.__class__')
    class_examples = get_customizations_for(algo, 'examples.__class__')
    class_extras = get_customizations_for(algo, 'extensions.__class__')
    module_extras = get_customizations_for(algo, 'extensions.__module__')

    update_param_defaults = get_customizations_for('defaults', 'update_param')
    update_param = get_customizations_for(algo, 'update_param')
    deprecated_params = get_customizations_for(algo, 'deprecated_params', {})

    def extend_schema_params(param):
        pname = param.get('name')
        param = deepcopy(param)
        updates = None
        for update_fn in [update_param, update_param_defaults]:
            if callable(update_fn):
                updates = update_fn(pname, param)
            if updates is not None:
                param = updates
                break
        # return param if isinstance(param, (list, tuple)) else [param]  # always return array to support deprecated aliases
        return param

    extended_params = [extend_schema_params(p) for p in schema['parameters']]

    param_names = []
    for param in extended_params:
        pname = param.get('name')
        ptype = param.get('type')
        pvalues = param.get('values')
        pdefault = param.get('default_value')

        assert (ptype[:4] == 'enum'
                ) == bool(pvalues), "Values are expected for enum types only"
        if pvalues:
            enum_values = [normalize_enum_constant(p) for p in pvalues]
            if pdefault:
                pdefault = normalize_enum_constant(pdefault)
        else:
            enum_values = None

        if pname in reserved_words:
            pname += "_"
        param_names.append(pname)
        param['pname'] = pname
        param['default_value'] = pdefault
        param['ptype'] = translate_type_for_check(ptype, enum_values)
        param['dtype'] = translate_type_for_doc(ptype, enum_values)

    if deprecated_params:
        extended_params = [
            p for p in extended_params
            if p['pname'] not in deprecated_params.keys()
        ]

    yield "#!/usr/bin/env python"
    yield "# -*- encoding: utf-8 -*-"
    yield "#"
    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_python.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield "#"
    yield "from __future__ import absolute_import, division, print_function, unicode_literals"
    yield ""
    if deprecated_params:
        yield "from h2o.utils.metaclass import deprecated_params, deprecated_property"
    if extra_imports:
        yield reformat_block(extra_imports)
    yield "from h2o.estimators.estimator_base import H2OEstimator"
    yield "from h2o.exceptions import H2OValueError"
    yield "from h2o.frame import H2OFrame"
    yield "from h2o.utils.typechecks import assert_is_type, Enum, numeric"
    yield ""
    yield ""
    yield "class %s(H2OEstimator):" % classname
    yield '    """'
    yield "    " + schema["algo_full_name"]
    yield ""
    if class_doc:
        yield reformat_block(class_doc, 4)
    if class_examples:
        yield ""
        yield "    :examples:"
        yield ""
        yield reformat_block(class_examples, 4)
    yield '    """'
    yield ""
    yield '    algo = "%s"' % algo
    yield "    supervised_learning = %s" % get_customizations_for(
        algo, 'supervised_learning', True)
    options = get_customizations_for(algo, 'options')
    if options:
        yield "    _options_ = %s" % reformat_block(
            pformat(options), prefix=' ' * 16, prefix_first=False)
    yield ""
    if deprecated_params:
        yield reformat_block("@deprecated_params(%s)" % deprecated_params,
                             indent=4)
    init_sig = "def __init__(self,\n%s\n):" % "\n".join(
        "%s=%s,  # type: %s" %
        (name, default, "Optional[%s]" % type if default is None else type)
        for name, default, type in [(
            p.get('pname'), stringify(p.get('default_value'), infinity=None),
            p.get('dtype')) for p in extended_params])
    yield reformat_block(init_sig,
                         indent=4,
                         prefix=' ' * 13,
                         prefix_first=False)
    yield '        """'
    for p in extended_params:
        pname, pdefault, dtype, pdoc = p.get('pname'), stringify(
            p.get('default_value')), p.get('dtype'), p.get('help')
        pdesc = "%s: %s\nDefaults to ``%s``." % (pname, pdoc, pdefault)
        pident = ' ' * 15
        yield "        :param %s" % bi.wrap(
            pdesc, indent=pident, indent_first=False)
        yield "        :type %s: %s%s" % (
            pname, bi.wrap(dtype, indent=pident, indent_first=False),
            ", optional" if pdefault is None else "")
    yield '        """'
    yield "        super(%s, self).__init__()" % classname
    yield "        self._parms = {}"
    for p in extended_params:
        pname = p.get('pname')
        if pname == 'model_id':
            yield "        self._id = self._parms['model_id'] = model_id"
        else:
            yield "        self.%s = %s" % (pname, pname)
    rest_api_version = get_customizations_for(algo, 'rest_api_version')
    if rest_api_version:
        yield '        self._parms["_rest_version"] = %s' % rest_api_version
    yield ""
    for param in extended_params:
        pname = param.get('pname')
        if pname == "model_id":
            continue  # The getter is already defined in ModelBase
        sname = pname[:-1] if pname[-1] == '_' else pname
        ptype = param.get('ptype')
        dtype = param.get('dtype')
        pdefault = param.get('default_value')

        if dtype.startswith("Enum"):
            vals = dtype[5:-1].split(", ")
            property_doc = "One of: " + ", ".join("``%s``" % v for v in vals)
        else:
            property_doc = "Type: ``%s``" % dtype
        property_doc += ("." if pdefault is None else ", defaults to ``%s``." %
                         stringify(pdefault))

        yield "    @property"
        yield "    def %s(self):" % pname
        yield '        """'
        yield bi.wrap(param.get('help'), indent=8 *
                      ' ')  # we need to wrap only for text coming from server
        yield ""
        yield bi.wrap(property_doc, indent=8 * ' ')
        custom_property_doc = get_customizations_for(algo,
                                                     "doc.{}".format(pname))
        if custom_property_doc:
            yield ""
            yield reformat_block(custom_property_doc, 8)
        property_examples = get_customizations_for(algo,
                                                   "examples.{}".format(pname))
        if property_examples:
            yield ""
            yield "        :examples:"
            yield ""
            yield reformat_block(property_examples, 8)
        yield '        """'
        property_getter = get_customizations_or_defaults_for(
            algo, "overrides.{}.getter".format(
                pname))  # check gen_stackedensemble.py for an example
        if property_getter:
            yield reformat_block(property_getter.format(**locals()), 8)
        else:
            yield "        return self._parms.get(\"%s\")" % sname

        yield ""
        yield "    @%s.setter" % pname
        yield "    def %s(self, %s):" % (pname, pname)
        property_setter = get_customizations_or_defaults_for(
            algo, "overrides.{}.setter".format(
                pname))  # check gen_stackedensemble.py for an example
        if property_setter:
            yield reformat_block(property_setter.format(**locals()), 8)
        elif "H2OFrame" in ptype:
            yield "        self._parms[\"%s\"] = H2OFrame._validate(%s, '%s')" % (
                sname, pname, pname)
        else:
            yield "        assert_is_type(%s, None, %s)" % (pname, ptype)
            yield "        self._parms[\"%s\"] = %s" % (sname, pname)
        yield ""

    for old, new in deprecated_params.items():
        new_name = new[0] if isinstance(new, tuple) else new
        yield "    %s = deprecated_property('%s', %s)" % (old, old, new)

    yield ""
    if class_extras:
        yield reformat_block(code_as_str(class_extras), 4)
    if module_extras:
        yield ""
        yield reformat_block(code_as_str(module_extras))
Example #25
0
def gen_module(schema, algo, module):
    help_preamble = help_preamble_for(algo)
    help_details = help_details_for(algo)
    help_return = help_return_for(algo)
    help_epilogue = help_epilogue_for(algo)
    help_references = help_references_for(algo)
    help_example = help_example_for(algo)
    help_extra_params = help_extra_params_for(algo)
    help_extra_checks = help_extra_checks_for(algo)
    help_afterword = help_afterword_for(algo)
    model_name = algo_to_modelname(algo)

    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_R.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details) \n#'"
    yield "# -------------------------- %s -------------------------- #" % model_name
    if help_preamble:
        lines = help_preamble.split("\n")
        for line in lines:
            yield "#' %s" % line.lstrip()

    if help_extra_params:
        lines = help_extra_params.split("\n")
        for line in lines:
            yield line.lstrip()

    for param in schema["parameters"]:
        if param["name"] in ["ignored_columns", "response_column", "max_confusion_matrix_size"]:
            continue
        if algo == "naivebayes":
            if param["name"] == "min_sdev":
                yield "#' @param threshold The minimum standard deviation to use for observations without enough data. "
                yield "#'                  Must be at least 1e-10."
                continue
            if param["name"] == "eps_sdev":
                yield "#' @param eps A threshold cutoff to deal with numeric instability, must be positive."
                continue
            if param["name"] in ["min_prob", "eps_prob"]:
                continue
        if param["name"] == "seed":
            yield "#' @param seed Seed for random numbers (affects certain parts of the algo that are stochastic and those might or might not be enabled by default)"
            if algo in ["deeplearning", "deepwater"]:
                yield "#'        Note: only reproducible when running single threaded."
            yield "#'        Defaults to -1 (time-based random number)."
            continue
        phelp = param["help"]
        if param["type"] == "boolean":
            phelp = "\code{Logical}. " + phelp
        if param["values"]:
            phelp += " Must be one of: %s." % ", ".join('"%s"' % p for p in param["values"])
        if param["default_value"] is not None:
            phelp += " Defaults to %s." % normalize_value(param, True)
        yield "#' @param %s %s" % (param["name"], bi.wrap(phelp, indent=("#'        "), indent_first=False))
    if help_details:
        yield "#' @details %s" % bi.wrap(help_details, indent=("#'          "), indent_first=False)
    if help_return:
        lines = help_return.split("\n")
        for line in lines:
            yield "%s" % line.lstrip()
        # yield "#' @return %s" % bi.wrap(help_return, indent=("#'         "), indent_first=False)
    if help_epilogue:
        yield "#' @seealso %s" % bi.wrap(help_epilogue, indent=("#'          "), indent_first=False)
    if help_references:
        yield "#' @references %s" % help_references
    if help_example:
        yield "#' @examples"
        lines = help_example.split("\n")
        for line in lines:
            yield "#' %s" % line.lstrip()
    yield "#' @export"
    yield "h2o.%s <- function(%s," % (module, get_extra_params_for(algo))
    # yield indent("training_frame,", 17 + len(algo))
    list = []
    for param in schema["parameters"]:
        if param["name"] in ["ignored_columns", "response_column", "max_confusion_matrix_size", "training_frame"]:
            continue
        if algo == "naivebayes":
            if param["name"] == "min_sdev":
                list.append(indent("threshold = %s" % normalize_value(param), 17 + len(module)))
                continue
            if param["name"] == "eps_sdev":
                list.append(indent("eps = %s" % normalize_value(param), 17 + len(module)))
                continue
            if param["name"] in ["min_prob", "eps_prob"]:
                continue
        list.append(indent("%s = %s" % (param["name"], normalize_value(param)), 17 + len(module)))
    yield ",\n".join(list)
    yield indent(") \n{", 17 + len(module))
    if algo in ["deeplearning", "deepwater", "drf", "gbm", "glm", "naivebayes", "stackedensemble"]:
        yield "  #If x is missing, then assume user wants to use all columns as features."
        yield "  if(missing(x)){"
        yield "     if(is.numeric(y)){"
        yield "         x <- setdiff(col(training_frame),y)"
        yield "     }else{"
        yield "         x <- setdiff(colnames(training_frame),y)"
        yield "     }"
        yield "  }"
        if algo == "gbm":
            yield "  # Required maps for different names params, including deprecated params"
            yield "  .gbm.map <- c(\"x\" = \"ignored_columns\","
            yield "                \"y\" = \"response_column\")"
        elif algo == "naivebayes":
            yield " .naivebayes.map <- c(\"x\" = \"ignored_columns\", \"y\" = \"response_column\", \n \
                         \"threshold\" = \"min_sdev\", \"eps\" = \"eps_sdev\")"
        elif algo == "glm":
            yield "  # if (!is.null(beta_constraints)) {"
            yield "  #     if (!inherits(beta_constraints, 'data.frame') && !is.H2OFrame(beta_constraints))"
            yield "  #       stop(paste('`beta_constraints` must be an H2OH2OFrame or R data.frame. Got: ', class(beta_constraints)))"
            yield "  #     if (inherits(beta_constraints, 'data.frame')) {"
            yield "  #       beta_constraints <- as.h2o(beta_constraints)"
            yield "  #     }"
            yield "  # }"
            yield "  if (inherits(beta_constraints, 'data.frame')) {"
            yield "    beta_constraints <- as.h2o(beta_constraints)"
            yield "  }"
    yield ""
    yield "  # Required args: training_frame"
    yield "  if( missing(training_frame) ) stop(\"argument \'training_frame\' is missing, with no default\")"
    # yield "  if( missing(validation_frame) ) validation_frame = NULL"
    yield "  # Training_frame must be a key or an H2OFrame object"
    yield "  if (!is.H2OFrame(training_frame))"
    yield "     tryCatch(training_frame <- h2o.getFrame(training_frame),"
    yield "           error = function(err) {"
    yield "             stop(\"argument \'training_frame\' must be a valid H2OFrame or key\")"
    yield "           })"
    if algo not in ["stackedensemble", "word2vec"]:
        yield "  # Validation_frame must be a key or an H2OFrame object"
        yield "  if (!is.null(validation_frame)) {"
        yield "     if (!is.H2OFrame(validation_frame))"
        yield "         tryCatch(validation_frame <- h2o.getFrame(validation_frame),"
        yield "             error = function(err) {"
        yield "                 stop(\"argument \'validation_frame\' must be a valid H2OFrame or key\")"
        yield "             })"
        yield "  }"
    yield "  # Parameter list to send to model builder"
    yield "  parms <- list()"
    yield "  parms$training_frame <- training_frame"
    if algo == "glrm":
        yield " if(!missing(cols))"
        yield " parms$ignored_columns <- .verify_datacols(training_frame, cols)$cols_ignore"
    elif algo in ["deeplearning", "deepwater", "drf", "gbm", "glm", "naivebayes", "stackedensemble"]:
        if any(param["name"] == "autoencoder" for param in schema["parameters"]):
            yield "  args <- .verify_dataxy(training_frame, x, y, autoencoder)"
        else:
            yield "  args <- .verify_dataxy(training_frame, x, y)"
        if any(param["name"] == "offset_column" for param in schema["parameters"]):
            yield "  if( !missing(offset_column) && !is.null(offset_column))  args$x_ignore <- args$x_ignore[!( offset_column == args$x_ignore )]"
        if any(param["name"] == "weights_column" for param in schema["parameters"]):
            yield "  if( !missing(weights_column) && !is.null(weights_column)) args$x_ignore <- args$x_ignore[!( weights_column == args$x_ignore )]"
        if algo != "stackedensemble":
            yield "  if( !missing(fold_column) && !is.null(fold_column)) args$x_ignore <- args$x_ignore[!( fold_column == args$x_ignore )]"
            yield "  parms$ignored_columns <- args$x_ignore"
        yield "  parms$response_column <- args$y\n"
    elif algo == "word2vec":
        yield ""
    else:
        yield "  if(!missing(x))"
        yield "    parms$ignored_columns <- .verify_datacols(training_frame, x)$cols_ignore"
    if algo == "svd":
        yield "  if(!missing(destination_key)) {"
        yield "    warning(\"'destination_key' is deprecated; please use 'model_id' instead.\")"
        yield "    if(missing(model_id)) {"
        yield "      parms$model_id <- destination_key"
        yield "    }"
        yield "  }"
    if algo == "stackedensemble":
        yield "  if (!missing(model_id))"
        yield "    parms$model_id <- model_id"
    for param in schema["parameters"]:
        if param["name"] in ["ignored_columns", "response_column", "training_frame", "max_confusion_matrix_size"]:
            continue
        if algo == "glm" and param["name"] in ["interactions", "nfolds", "beta_constraints", "missing_values_handling"]:
            continue
        if param["name"] == "loss":
            yield "  if(!missing(loss)) {"
            yield "    if(loss == \"MeanSquare\") {"
            yield "      warning(\"Loss name 'MeanSquare' is deprecated; please use 'Quadratic' instead.\")"
            yield "      parms$loss <- \"Quadratic\""
            yield "    } else "
            yield "      parms$loss <- loss"
            yield "  }"
            continue
        if param["name"] in ["min_sdev", "min_prob"]:
            yield " if (!missing(threshold))"
            yield "   parms$%s <- threshold" % param["name"]
            continue
        if param["name"] in ["eps_sdev", "eps_prob"]:
            yield " if (!missing(eps))"
            yield "   parms$%s <- eps" % param["name"]
            continue
        yield "  if (!missing(%s))" % param["name"]
        yield "    parms$%s <- %s" % (param["name"], param["name"])
    if help_extra_checks:
        lines = help_extra_checks.split("\n")
        for line in lines:
            yield "%s" % line
    if algo != "glm":
        yield "  # Error check and build model"
        yield "  .h2o.modelJob('%s', parms, h2oRestApiVersion=%d) \n}" % (algo, 99 if algo in ["svd", "stackedensemble"] else 3)
    if help_afterword:
        lines = help_afterword.split("\n")
        for line in lines:
            yield line.lstrip()
Example #26
0
def generate_main_class(endpoints):
    yield "/**"
    yield " * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_java.py"
    yield " * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield " */"
    yield "package water.bindings;"
    yield ""
    yield "import water.bindings.pojos.*;"
    yield "import water.bindings.proxies.retrofit.*;"
    yield "import retrofit2.*;"
    yield "import retrofit2.converter.gson.GsonConverterFactory;"
    yield "import com.google.gson.*;"
    yield "import okhttp3.OkHttpClient;"
    yield "import java.io.IOException;"
    yield "import java.lang.reflect.Type;"
    yield "import java.util.concurrent.TimeUnit;"
    yield ""
    yield "public class H2oApi {"
    yield ""
    yield "  public H2oApi() {}"
    yield "  public H2oApi(String url) { this.url = url; }"
    yield ""
    yield "  public H2oApi setUrl(String s) {"
    yield "    url = s;"
    yield "    retrofit = null;"
    yield "    return this;"
    yield "  }"
    yield ""
    yield "  public H2oApi setTimeout(int t) {"
    yield "    timeout_s = t;"
    yield "    retrofit = null;"
    yield "    return this;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   * Set time interval for job polling in {@link #waitForJobCompletion(JobKeyV3)}."
    yield "   *   @param millis time interval, in milliseconds"
    yield "   */"
    yield "  public H2oApi setJobPollInterval(int millis) {"
    yield "    pollInterval_ms = millis;"
    yield "    return this;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   * Continuously poll server for the status of the given job, until it completes."
    yield "   *   @param jobKey job to query"
    yield "   *   @return the finished job"
    yield "   */"
    yield "  public JobV3 waitForJobCompletion(JobKeyV3 jobKey) {"
    yield "    return waitForJobCompletion(keyToString(jobKey));"
    yield "  }"
    yield "  public JobV3 waitForJobCompletion(String jobId) {"
    yield "    Jobs jobService = getService(Jobs.class);"
    yield "    Response<JobsV3> jobsResponse = null;"
    yield "    int retries = 3;"
    yield "    JobsV3 jobs = null;"
    yield "    do {"
    yield "      try {"
    yield "        Thread.sleep(pollInterval_ms);"
    yield "        jobsResponse = jobService.fetch(jobId).execute();"
    yield "      } catch (IOException e) {"
    yield "        System.err.println(\"Caught exception: \" + e);"
    yield "      } catch (InterruptedException e) { /* pass */ }"
    yield "      if (jobsResponse == null || !jobsResponse.isSuccessful())"
    yield "        if (retries-- > 0)"
    yield "          continue;"
    yield "        else"
    yield "          throw new RuntimeException(\"/3/Jobs/\" + jobId + \" failed 3 times.\");"
    yield "      jobs = jobsResponse.body();"
    yield "      if (jobs.jobs == null || jobs.jobs.length != 1)"
    yield "        throw new RuntimeException(\"Failed to find Job: \" + jobId);"
    yield "    } while (jobs != null && jobs.jobs[0].status.equals(\"RUNNING\"));"
    yield "    return jobs == null? null : jobs.jobs[0];"
    yield "  }"
    yield ""

    for route in endpoints:
        apiname = route["api_name"]
        class_name = route["class_name"]
        outtype = route["output_schema"]
        input_fields = route["input_params"]
        required_fields = [field  for field in input_fields if field["required"]]
        input_fields_wo_excluded = [field  for field in input_fields if field["name"] != "_exclude_fields"]

        yield "  /**"
        yield bi.wrap(route["summary"], indent="   * ")
        yield "   */"
        # Make several versions of each API call:
        #  (1) Only the required parameters
        #  (2) All parameters except the _excluded_fields
        #  (3) All parameters
        li = len(input_fields)
        le = len(input_fields_wo_excluded)
        lr = len(required_fields)
        assert lr <= 3, "Too many required fields in method " + apiName
        if lr == li:
            # The set of required fields is the same as the set of input fields. No need for (2) and (3).
            input_fields = None
            input_fields_wo_excluded = None
        elif le == li or le == lr or li >= 4:
            # If set (2) coincides with either (1) or (3), then we will not generate code for it.
            # Additionally, if there are too many input params so that we will put them into a container class,
            # then there will be no need for separate case (2) either.
            input_fields_wo_excluded = None

        # Temporary hack, since Parse reuires all the fields from ParseSetup: don't generate the required-fields-only method
        if 'parse' == apiname:
            required_fields = None

        for fields in [required_fields, input_fields_wo_excluded, input_fields]:
            if fields is None: continue
            use_schema_param = (len(fields) >= 4)
            value_field_strs = []
            typed_field_strs = []
            for field in fields:
                ftype = translate_type(field["type"], field["schema_name"])
                fname = translate_name(field["name"])
                typed_field_strs.append("%s %s" % (ftype, fname))
                if use_schema_param: fname = "params." + fname
                if ftype.endswith("KeyV3"):
                    s = "keyToString(%s)" % fname
                elif ftype.endswith("KeyV3[]"):
                    s = "keyArrayToStringArray(%s)" % fname
                elif ftype.startswith("ColSpecifier"):
                    s = "colToString(%s)" % fname
                else:
                    s = fname
                value_field_strs.append(s)

            if use_schema_param:
                args = route["input_schema"] + " params"
                values = "\n      " + ",\n      ".join(value_field_strs) + "\n    "
            else:
                args = ", ".join(typed_field_strs)
                values = ", ".join(value_field_strs)
                if fields == input_fields_wo_excluded:
                    values += ", \"\""

            yield "  public {type} {method}({args}) throws IOException {{".\
                  format(type=outtype, method=apiname, args=args)
            yield "    {clazz} s = getService({clazz}.class);".format(clazz=class_name)
            yield "    return s.{method}({values}).execute().body();".\
                  format(method=route["handler_method"], values=values);
            yield "  }"
        yield ""

    yield ""
    yield "  //--------- PRIVATE " + "-"*98
    yield ""
    yield "  private Retrofit retrofit;"
    yield "  private String url = \"http://*****:*****@Override"
    yield "    public JsonElement serialize(KeyV3 key, Type typeOfKey, JsonSerializationContext context) {"
    yield "      return new JsonPrimitive(key.name);"
    yield "    }"
    yield "  }"
    yield "  private static class ColSerializer implements JsonSerializer<ColSpecifierV3> {"
    yield "    @Override"
    yield "    public JsonElement serialize(ColSpecifierV3 col, Type typeOfCol, JsonSerializationContext context) {"
    yield "      return new JsonPrimitive(col.columnName);"
    yield "    }"
    yield "  }"
    yield "  /**"
    yield "   * Factory method for parsing a ModelsV3 json object into an instance of the model-specific subclass."
    yield "   */"
    yield "  private static class ModelDeserializer implements JsonDeserializer<ModelsV3> {"
    yield "    @Override"
    yield "    public ModelsV3 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)"
    yield "      throws JsonParseException {"
    yield "      if (json.isJsonNull()) return null;"
    yield "      if (json.isJsonObject()) {"
    yield "        JsonObject jobj = json.getAsJsonObject();"
    yield "        if (jobj.has(\"algo\")) {"
    yield "          String algo = jobj.get(\"algo\").getAsJsonPrimitive().getAsString().toLowerCase();"
    yield "          switch (algo) {"
    for route in endpoints:
        if route["class_name"] == "ModelBuilders" and route["api_name"].startswith("train"):
            algo = route["algo"]
            oschema = route["output_schema"]
            assert oschema.lower()[:len(algo)] == algo, "Wrong output schema for algo %s: %s" % (algo, oschema)
            model = oschema[:len(algo)] + "Model" + oschema[len(algo):]  # "DeepLearningV3" => "DeepLearningModelV3"
            yield "            case \"{algo}\": return context.deserialize(json, {model}.class);".format(**locals())
    yield "            default:"
    yield "              throw new JsonParseException(\"Unable to deserialize model of type \" + algo);"
    yield "          }"
    yield "        }"
    yield "      }"
    yield "      throw new JsonParseException(\"Invalid ModelsV3 element \" + json.toString());"
    yield "    }"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   * Return an array of Strings for an array of keys."
    yield "   */"
    yield "  public static String[] keyArrayToStringArray(KeyV3[] keys) {"
    yield "    if (keys == null) return null;"
    yield "    String[] ids = new String[keys.length];"
    yield "    int i = 0;"
    yield "    for (KeyV3 key : keys) ids[i++] = key.name;"
    yield "    return ids;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   * Return an array of Keys for an array of Strings."
    yield "   */"
    yield "  public static FrameKeyV3[] stringArrayToFrameKeyArray(String[] keys) {"
    yield "    if (keys == null) return null;"
    yield "    FrameKeyV3[] ids = new FrameKeyV3[keys.length];"
    yield "    int i = 0;"
    yield "    for (String key : keys) { FrameKeyV3 k = new FrameKeyV3(); k.name = key; ids[i++] = k; }"
    yield "    return ids;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   *"
    yield "   */"
    yield "  public static String keyToString(KeyV3 key) {"
    yield "    return key == null? null : key.name;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   *"
    yield "   */"
    yield "  public static FrameKeyV3 stringToFrameKey(String key) {"
    yield "    if (key == null) return null;"
    yield "    FrameKeyV3 k = new FrameKeyV3();"
    yield "    k.name = key;"
    yield "    return k;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   *"
    yield "   */"
    yield "  private static String colToString(ColSpecifierV3 col) {"
    yield "    return col == null? null : col.columnName;"
    yield "  }"
    yield ""
    yield "  /**"
    yield "   *"
    yield "   */"
    yield "  public static String stringToCol(String col) {"
    yield "    if (col == null) return null;"
    yield "    ColSpecifierV3 c = new ColSpecifierV3();"
    yield "    c.columnName = col;"
    yield "    return col;"
    yield "  }"
    yield ""
    yield "}"
Example #27
0
def generate_proxy(classname, endpoints):
    """
    Retrofit interfaces look like this:
        public interface GitHubService {
            @GET("/users/{user}/repos")
            Call<List<Repo>> listRepos(@Path("user") String user);
        }
      :param classname: name of the class
      :param endpoints: list of endpoints served by this class
    """

    # Replace path vars like (?<schemaname>.*) with {schemaname} for Retrofit's annotation
    var_pattern = re.compile(r"\{(\w+)\}")

    helper_class = []
    found_key_array_parameter = False

    yield "/**"
    yield " * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_java.py"
    yield " * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield " */"
    yield "package water.bindings.proxies.retrofit;"
    yield ""
    yield "import water.bindings.pojos.*;"
    yield "import retrofit2.*;"
    yield "import retrofit2.http.*;"
    yield ""
    yield "public interface " + classname + " {"
    yield ""

    for e in endpoints:
        method = e["handler_method"]

        param_strs = []
        required_param_strs = []
        for field in e["input_params"]:
            fname = field["name"]
            ftype = "Path" if field["is_path_param"] else "Field"
            ptype = translate_type(field["type"], field["schema_name"])
            if ptype.endswith("KeyV3") or ptype == "ColSpecifierV3": ptype = "String"
            if ptype.endswith("KeyV3[]"): ptype = "String[]"
            param_str = "@{ftype}(\"{fname}\") {ptype} {fname}".format(**locals())
            param_strs.append(param_str)
            if field["required"]:
                required_param_strs.append(param_str)
        if len(param_strs) == len(required_param_strs): required_param_strs = None

        yield u"  /** "
        yield bi.wrap(e["summary"], indent="   * ")
        for field in e["input_params"]:
            s = "   *   @param %s " % field["name"]
            yield s + bi.wrap(field["help"], indent="   *"+" "*(len(s)-4), indent_first=False)
        yield u"   */"
        # Create 2 versions of each call: first with all input parameters present, and then only with required params
        for params in [param_strs, required_param_strs]:
            if params is None: continue
            yield u"  @FormUrlEncoded" if e["http_method"] == "POST" else None
            yield u"  @{method}(\"{path}\")".format(method=e["http_method"], path=e["url_pattern"])
            if len(params) <= 1:
                args = params[0] if params else ""
                yield "  Call<{schema}> {method}({args});".format(schema=e["output_schema"], method=method, args=args)
            else:
                yield "  Call<{schema}> {method}(".format(schema=e["output_schema"], method=method)
                for arg in params:
                    yield "    " + arg + ("" if arg == params[-1] else ",")
                yield "  );"
            yield ""

        # Make special static Helper class for Grid and ModelBuilders.
        if "algo" in e:
            # We make two train_ and validate_ methods.  One (built here) takes the parameters schema, the other
            # (built above) takes each parameter.
            helper_class.append("    /**")
            helper_class.append(bi.wrap(e["summary"], indent="     * "))
            helper_class.append("     */")
            helper_class.append("    public static Call<{oschema}> {method}({outer_class} z, {ischema} p) {{"
                                .format(ischema=e["input_schema"], oschema=e["output_schema"], method=method,
                                        outer_class=classname))
            helper_class.append("      return z.{method}(".format(method=method))
            for field in e["input_params"]:
                ptype = translate_type(field["type"], field["schema_name"])
                pname = translate_name(field["name"])
                if ptype.endswith("KeyV3"):
                    s = "(p.{parm} == null? null : p.{parm}.name)".format(parm=pname)
                elif ptype.endswith("KeyV3[]"):
                    found_key_array_parameter = True
                    s = "(p.{parm} == null? null : keyArrayToStringArray(p.{parm}))".format(parm=pname)
                elif ptype.startswith("ColSpecifier"):
                    s = "(p.{parm} == null? null : p.{parm}.columnName)".format(parm=pname)
                else:
                    s = "p." + pname
                if field != e["input_params"][-1]:
                    s += ","
                helper_class.append("        " + s)
            helper_class.append("      );")
            helper_class.append("    }")
            helper_class.append("")

    if helper_class:
        yield ""
        yield "  class Helper {"
        for line in helper_class:
            yield line
        if found_key_array_parameter:
            yield "    /**"
            yield "     * Return an array of Strings for an array of keys."
            yield "     */"
            yield "    public static String[] keyArrayToStringArray(KeyV3[] keys) {"
            yield "      if (keys == null) return null;"
            yield "      String[] ids = new String[keys.length];"
            yield "      int i = 0;"
            yield "      for (KeyV3 key : keys) ids[i++] = key.name;"
            yield "      return ids;"
            yield "    }"
        yield "  }"
        yield ""

    yield "}"
Example #28
0
def generate_proxy(classname, endpoints):
    """
    Generate a Retrofit Proxy class.

    Retrofit interfaces look like this:
        public interface GitHubService {
            @GET("/users/{user}/repos")
            Call<List<Repo>> listRepos(@Path("user") String user);
        }
      :param classname: name of the class
      :param endpoints: list of endpoints served by this class
    """
    # Replace path vars like (?<schemaname>.*) with {schemaname} for Retrofit's annotation
    var_pattern = re.compile(r"\{(\w+)\}")

    helper_class = []
    found_key_array_parameter = False

    yield "/*"
    yield " * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_java.py"
    yield " * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield " */"
    yield "package water.bindings.proxies.retrofit;"
    yield ""
    yield "import water.bindings.pojos.*;"
    yield "import retrofit2.*;"
    yield "import retrofit2.http.*;"
    yield "import java.util.Map;" if classname == "Grid" or classname == "ModelBuilders" else None
    yield ""
    yield "public interface " + classname + " {"
    yield ""

    for e in endpoints:
        method = e["handler_method"]
        # should we always use e.api_name ?
        if method == "exec":
            method = e["api_name"]

        param_strs = []
        required_param_strs = []
        for field in e["input_params"]:
            fname = field["name"]
            if field["is_path_param"]:
                ftype = "Path"
            else:
                if e["http_method"] == "GET":
                    ftype = "Query"
                else:
                    ftype = "Field"
            ptype = translate_type(field["type"], field["schema_name"])
            if ptype.endswith("KeyV3") or ptype == "ColSpecifierV3":
                ptype = "String"
            if ptype.endswith("KeyV3[]"): ptype = "String[]"
            param_str = "@{ftype}(\"{fname}\") {ptype} {fname}".format(
                **locals())
            param_strs.append(param_str)
            if field["required"]:
                required_param_strs.append(param_str)
        if len(param_strs) == len(required_param_strs):
            required_param_strs = None

        yield u"  /** "
        yield bi.wrap(e["summary"], indent="   * ")
        for field in e["input_params"]:
            s = "   *   @param %s " % field["name"]
            yield s + bi.wrap(field["help"],
                              indent="   *" + " " * (len(s) - 4),
                              indent_first=False)
        yield u"   */"
        # Create 2 versions of each call: first with all input parameters present, and then only with required params
        for params in [param_strs, required_param_strs]:
            if params is None: continue
            yield u"  @FormUrlEncoded" if e["http_method"] == "POST" else None
            yield u"  @{method}(\"{path}\")".format(method=e["http_method"],
                                                    path=e["url_pattern"])
            if len(params) <= 1:
                args = params[0] if params else ""
                yield "  Call<{schema}> {method}({args});".format(
                    schema=e["output_schema"], method=method, args=args)
            else:
                yield "  Call<{schema}> {method}(".format(
                    schema=e["output_schema"], method=method)
                for arg in params:
                    yield "    " + arg + ("" if arg == params[-1] else ",")
                yield "  );"
            yield ""

        # Make special static Helper class for Grid and ModelBuilders.
        if "algo" in e:
            # We make two train_ and validate_ methods.  One (built here) takes the parameters schema, the other
            # (built above) takes each parameter.
            helper_class.append("    /**")
            helper_class.append(bi.wrap(e["summary"], indent="     * "))
            helper_class.append("     */")
            helper_class.append(
                "    public static Call<{oschema}> {method}({outer_class} z, {ischema} p) {{"
                .format(ischema=e["input_schema"],
                        oschema=e["output_schema"],
                        method=method,
                        outer_class=classname))
            helper_class.append(
                "      return z.{method}(".format(method=method))
            for field in e["input_params"]:
                ptype = translate_type(field["type"], field["schema_name"])
                pname = translate_name(field["name"])
                if ptype.endswith("KeyV3"):
                    s = "(p.{parm} == null? null : p.{parm}.name)".format(
                        parm=pname)
                elif ptype.endswith("KeyV3[]"):
                    found_key_array_parameter = True
                    s = "(p.{parm} == null? null : keyArrayToStringArray(p.{parm}))".format(
                        parm=pname)
                elif ptype == "ColSpecifierV3":
                    s = "(p.{parm} == null? null : p.{parm}.columnName)".format(
                        parm=pname)
                else:
                    s = "p." + pname
                if field != e["input_params"][-1]:
                    s += ","
                helper_class.append("        " + s)
            helper_class.append("      );")
            helper_class.append("    }")
            helper_class.append("")

    if helper_class:
        yield ""
        yield "  @SuppressWarnings(\"unused\")"
        yield "  class Helper {"
        for line in helper_class:
            yield line
        if found_key_array_parameter:
            yield "    /**"
            yield "     * Return an array of Strings for an array of keys."
            yield "     */"
            yield "    public static String[] keyArrayToStringArray(KeyV3[] keys) {"
            yield "      if (keys == null) return null;"
            yield "      String[] ids = new String[keys.length];"
            yield "      int i = 0;"
            yield "      for (KeyV3 key : keys) ids[i++] = key.name;"
            yield "      return ids;"
            yield "    }"
        yield "  }"
        yield ""

    yield "}"
Example #29
0
def generate_schema(class_name, schema):
    """
    Generate schema POJO file.
      :param class_name: name of the class
      :param schema: information about the class
    """
    has_map = False
    is_model_builder = False
    has_inherited = False
    for field in schema["fields"]:
        if field["name"] == "__meta": continue
        if field["is_inherited"]:
            has_inherited = True
            continue
        if field["type"].startswith("Map"): has_map = True
        if field["name"] == "can_build": is_model_builder = True

    superclass = schema["superclass"]
    if superclass == "Schema": superclass = "Object"

    fields = []
    for field in schema["fields"]:
        if field["name"] == "__meta": continue
        java_type = translate_type(field["type"], field["schema_name"])
        java_value = get_java_value(field)

        # hackery: we flatten the parameters up into the ModelBuilder schema, rather than nesting them in the
        # parameters schema class...
        if False and is_model_builder and field["name"] == "parameters":
            fields.append(("parameters", "null", "ModelParameterSchemaV3[]", field["help"], field["is_inherited"]))
        else:
            fields.append((field["name"], java_value, java_type, field["help"], field["is_inherited"]))

    yield "/**"
    yield " * This file is auto-generated by h2o-3/h2o-bindings/bin/gen_java.py"
    yield " * Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details)"
    yield " */"
    yield "package water.bindings.pojos;"
    yield ""
    yield "import com.google.gson.Gson;"
    yield "import com.google.gson.annotations.*;"
    yield "import java.util.Map;" if has_map else None
    yield ""
    yield ""
    yield "public class %s extends %s {" % (class_name, superclass) if superclass != "Object" else None
    yield "public class %s {" % (class_name) if superclass == "Object" else None
    yield ""
    for name, value, ftype, fhelp, inherited in fields:
        if inherited: continue
        ccname = translate_name(name)
        yield "    /**"
        yield bi.wrap(fhelp, indent="     * ")
        yield "     */"
        yield "    @SerializedName(\"%s\")" % name  if name != ccname else None
        yield "    public %s %s;" % (ftype, ccname)
        yield ""
    if has_inherited:
        yield ""
        yield "    /*" + ("-" * 114)
        yield "    //" + (" " * 50) + "INHERITED"
        yield "    //" + ("-" * 114)
        yield ""
        for name, value, ftype, fhelp, inherited in fields:
            if not inherited: continue
            yield bi.wrap(fhelp, "    // ")
            yield "    public %s %s;" % (ftype, translate_name(name))
            yield ""
        yield "    */"
        yield ""
    yield "    /**"
    yield "     * Public constructor"
    yield "     */"
    yield "    public %s() {" % class_name
    for name, value, _, _, _ in fields:
        if name == "parameters": continue
        if value == "null": continue
        yield "        %s = %s;" % (translate_name(name), value)
    yield "    }"
    yield ""
    yield "    /**"
    yield "     * Return the contents of this object as a JSON String."
    yield "     */"
    yield "    @Override"
    yield "    public String toString() {"
    yield "        return new Gson().toJson(this);"
    yield "    }"
    yield ""
    yield "}"
Example #30
0
File: gen_R.py Project: h2oai/h2o-3
def gen_module(schema, algo, module):
    help_preamble = help_preamble_for(algo)
    help_details = help_details_for(algo)
    help_return = help_return_for(algo)
    help_epilogue = help_epilogue_for(algo)
    help_references = help_references_for(algo)
    help_example = help_example_for(algo)
    help_extra_params = help_extra_params_for(algo)
    help_extra_checks = help_extra_checks_for(algo)
    help_afterword = help_afterword_for(algo)
    model_name = algo_to_modelname(algo)

    yield "# This file is auto-generated by h2o-3/h2o-bindings/bin/gen_R.py"
    yield "# Copyright 2016 H2O.ai;  Apache License Version 2.0 (see LICENSE for details) \n#'"
    yield "# -------------------------- %s -------------------------- #" % model_name
    if help_preamble:
        lines = help_preamble.split("\n")
        for line in lines:
            yield "#' %s" % line.lstrip()

    if help_extra_params:
        lines = help_extra_params.split("\n")
        for line in lines:
            yield line.lstrip()

    for param in schema["parameters"]:
        if param["name"] in ["ignored_columns", "response_column", "max_confusion_matrix_size"]:
            continue
        if algo == "naivebayes":
            if param["name"] == "min_sdev":
                yield "#' @param threshold The minimum standard deviation to use for observations without enough data. "
                yield "#'                  Must be at least 1e-10."
                continue
            if param["name"] == "eps_sdev":
                yield "#' @param eps A threshold cutoff to deal with numeric instability, must be positive."
                continue
            if param["name"] in ["min_prob", "eps_prob"]:
                continue
        if param["name"] == "seed":
            yield "#' @param seed Seed for random numbers (affects certain parts of the algo that are stochastic and those might or might not be enabled by default)"
            if algo in ["deeplearning", "deepwater"]:
                yield "#'        Note: only reproducible when running single threaded."
            yield "#'        Defaults to -1 (time-based random number)."
            continue
        phelp = param["help"]
        if param["type"] == "boolean":
            phelp = "\code{Logical}. " + phelp
        if param["values"]:
            phelp += " Must be one of: %s." % ", ".join('"%s"' % p for p in param["values"])
        if param["default_value"] is not None:
            phelp += " Defaults to %s." % normalize_value(param, True)
        yield "#' @param %s %s" % (param["name"], bi.wrap(phelp, indent=("#'        "), indent_first=False))
    if help_details:
        yield "#' @details %s" % bi.wrap(help_details, indent=("#'          "), indent_first=False)
    if help_return:
        lines = help_return.split("\n")
        for line in lines:
            yield "%s" % line.lstrip()
        # yield "#' @return %s" % bi.wrap(help_return, indent=("#'         "), indent_first=False)
    if help_epilogue:
        yield "#' @seealso %s" % bi.wrap(help_epilogue, indent=("#'          "), indent_first=False)
    if help_references:
        yield "#' @references %s" % help_references
    if help_example:
        yield "#' @examples"
        lines = help_example.split("\n")
        for line in lines:
            yield "#' %s" % line.lstrip()
    yield "#' @export"
    yield "h2o.%s <- function(%s," % (module, get_extra_params_for(algo))
    # yield indent("training_frame,", 17 + len(algo))
    list = []
    for param in schema["parameters"]:
        if param["name"] in ["ignored_columns", "response_column", "max_confusion_matrix_size", "training_frame"]:
            continue
        if algo == "naivebayes":
            if param["name"] == "min_sdev":
                list.append(indent("threshold = %s" % normalize_value(param), 17 + len(module)))
                continue
            if param["name"] == "eps_sdev":
                list.append(indent("eps = %s" % normalize_value(param), 17 + len(module)))
                continue
            if param["name"] in ["min_prob", "eps_prob"]:
                continue
        list.append(indent("%s = %s" % (param["name"], normalize_value(param)), 17 + len(module)))
    yield ",\n".join(list)
    yield indent(") \n{", 17 + len(module))
    if algo in ["deeplearning", "deepwater", "drf", "gbm", "glm", "naivebayes", "stackedensemble"]:
        yield "  #If x is missing, then assume user wants to use all columns as features."
        yield "  if(missing(x)){"
        yield "     if(is.numeric(y)){"
        yield "         x <- setdiff(col(training_frame),y)"
        yield "     }else{"
        yield "         x <- setdiff(colnames(training_frame),y)"
        yield "     }"
        yield "  }"
        if algo == "gbm":
            yield "  # Required maps for different names params, including deprecated params"
            yield "  .gbm.map <- c(\"x\" = \"ignored_columns\","
            yield "                \"y\" = \"response_column\")"
        elif algo == "naivebayes":
            yield " .naivebayes.map <- c(\"x\" = \"ignored_columns\", \"y\" = \"response_column\", \n \
                         \"threshold\" = \"min_sdev\", \"eps\" = \"eps_sdev\")"
        elif algo == "glm":
            yield "  # if (!is.null(beta_constraints)) {"
            yield "  #     if (!inherits(beta_constraints, 'data.frame') && !is.H2OFrame(beta_constraints))"
            yield "  #       stop(paste('`beta_constraints` must be an H2OH2OFrame or R data.frame. Got: ', class(beta_constraints)))"
            yield "  #     if (inherits(beta_constraints, 'data.frame')) {"
            yield "  #       beta_constraints <- as.h2o(beta_constraints)"
            yield "  #     }"
            yield "  # }"
            yield "  if (inherits(beta_constraints, 'data.frame')) {"
            yield "    beta_constraints <- as.h2o(beta_constraints)"
            yield "  }"
    yield ""
    yield "  # Required args: training_frame"
    yield "  if( missing(training_frame) ) stop(\"argument \'training_frame\' is missing, with no default\")"
    # yield "  if( missing(validation_frame) ) validation_frame = NULL"
    yield "  # Training_frame must be a key or an H2OFrame object"
    yield "  if (!is.H2OFrame(training_frame))"
    yield "     tryCatch(training_frame <- h2o.getFrame(training_frame),"
    yield "           error = function(err) {"
    yield "             stop(\"argument \'training_frame\' must be a valid H2OFrame or key\")"
    yield "           })"
    if algo not in ["stackedensemble", "word2vec"]:
        yield "  # Validation_frame must be a key or an H2OFrame object"
        yield "  if (!is.null(validation_frame)) {"
        yield "     if (!is.H2OFrame(validation_frame))"
        yield "         tryCatch(validation_frame <- h2o.getFrame(validation_frame),"
        yield "             error = function(err) {"
        yield "                 stop(\"argument \'validation_frame\' must be a valid H2OFrame or key\")"
        yield "             })"
        yield "  }"
    yield "  # Parameter list to send to model builder"
    yield "  parms <- list()"
    yield "  parms$training_frame <- training_frame"
    if algo == "glrm":
        yield " if(!missing(cols))"
        yield " parms$ignored_columns <- .verify_datacols(training_frame, cols)$cols_ignore"
    elif algo in ["deeplearning", "deepwater", "drf", "gbm", "glm", "naivebayes", "stackedensemble"]:
        if any(param["name"] == "autoencoder" for param in schema["parameters"]):
            yield "  args <- .verify_dataxy(training_frame, x, y, autoencoder)"
        else:
            yield "  args <- .verify_dataxy(training_frame, x, y)"
        if any(param["name"] == "offset_column" for param in schema["parameters"]):
            yield "  if( !missing(offset_column) && !is.null(offset_column))  args$x_ignore <- args$x_ignore[!( offset_column == args$x_ignore )]"
        if any(param["name"] == "weights_column" for param in schema["parameters"]):
            yield "  if( !missing(weights_column) && !is.null(weights_column)) args$x_ignore <- args$x_ignore[!( weights_column == args$x_ignore )]"
        if algo != "stackedensemble":
            yield "  if( !missing(fold_column) && !is.null(fold_column)) args$x_ignore <- args$x_ignore[!( fold_column == args$x_ignore )]"
            yield "  parms$ignored_columns <- args$x_ignore"
        yield "  parms$response_column <- args$y\n"
    elif algo == "word2vec":
        yield ""
    else:
        yield "  if(!missing(x))"
        yield "    parms$ignored_columns <- .verify_datacols(training_frame, x)$cols_ignore"
    if algo == "svd":
        yield "  if(!missing(destination_key)) {"
        yield "    warning(\"'destination_key' is deprecated; please use 'model_id' instead.\")"
        yield "    if(missing(model_id)) {"
        yield "      parms$model_id <- destination_key"
        yield "    }"
        yield "  }"
    if algo == "stackedensemble":
        yield "  if (!missing(model_id))"
        yield "    parms$model_id <- model_id"
    for param in schema["parameters"]:
        if param["name"] in ["ignored_columns", "response_column", "training_frame", "max_confusion_matrix_size"]:
            continue
        if algo == "glm" and param["name"] in ["interactions", "nfolds", "beta_constraints", "missing_values_handling"]:
            continue
        if param["name"] == "loss":
            yield "  if(!missing(loss)) {"
            yield "    if(loss == \"MeanSquare\") {"
            yield "      warning(\"Loss name 'MeanSquare' is deprecated; please use 'Quadratic' instead.\")"
            yield "      parms$loss <- \"Quadratic\""
            yield "    } else "
            yield "      parms$loss <- loss"
            yield "  }"
            continue
        if param["name"] in ["min_sdev", "min_prob"]:
            yield " if (!missing(threshold))"
            yield "   parms$%s <- threshold" % param["name"]
            continue
        if param["name"] in ["eps_sdev", "eps_prob"]:
            yield " if (!missing(eps))"
            yield "   parms$%s <- eps" % param["name"]
            continue
        yield "  if (!missing(%s))" % param["name"]
        yield "    parms$%s <- %s" % (param["name"], param["name"])
    if help_extra_checks:
        lines = help_extra_checks.split("\n")
        for line in lines:
            yield "%s" % line
    if algo != "glm":
        yield "  # Error check and build model"
        yield "  .h2o.modelJob('%s', parms, h2oRestApiVersion=%d) \n}" % (algo, 99 if algo in ["svd", "stackedensemble"] else 3)
    if help_afterword:
        lines = help_afterword.split("\n")
        for line in lines:
            yield line.lstrip()