def put(self, key: str, outputs: Env.Bindings[Value.Base]) -> None:
        if not self._cfg["call_cache"].get_bool("put"):
            return

        def cache(v: Union[Value.File, Value.Directory]) -> str:
            _cached_files[inode(v.value)] = (key, outputs)
            return ""

        with _uploaded_files_lock:
            Value.rewrite_env_paths(outputs, cache)
            cache_put(self._cfg, self._logger, key, outputs)
Пример #2
0
 def _call_eager(self, expr: E.Apply, arguments: List[V.Base]) -> V.Base:
     ans_type = self.infer_type(expr)
     try:
         ans = self.op(arguments[0].coerce(ans_type).value, arguments[1].coerce(ans_type).value)
     except ZeroDivisionError:
         # TODO: different runtime error?
         raise Error.IncompatibleOperand(expr.arguments[1], "Division by zero") from None
     if ans_type == T.Int():
         assert isinstance(ans, int)
         return V.Int(ans)
     assert isinstance(ans, float)
     return V.Float(ans)
Пример #3
0
 def eval(self, env: Env.Values) -> V.Base:
     ""
     assert isinstance(self.type, T.Map)
     eitems = []
     for k, v in self.items:
         eitems.append((k.eval(env), v.eval(env)))
     # TODO: complain of duplicate keys
     return V.Map(self.type, eitems)
Пример #4
0
 def _call_eager(self, expr: E.Apply, arguments: List[V.Base]) -> V.Base:
     ans_type = self.infer_type(expr)
     if not isinstance(ans_type, T.String):
         return super()._call_eager(expr, arguments)
     # TODO: in a command interpolation, return missing if either operand is missing
     ans = self.op(
         str(arguments[0].coerce(T.String()).value), str(arguments[1].coerce(T.String()).value)
     )
     assert isinstance(ans, str)
     return V.String(ans)
Пример #5
0
def _basename(*args) -> V.String:
    assert len(args) in (1, 2)
    assert isinstance(args[0], V.String)
    path = args[0].value
    if len(args) > 1:
        assert isinstance(args[1], V.String)
        suffix = args[1].value
        if path.endswith(suffix):
            path = path[: -len(suffix)]
    return V.String(os.path.basename(path))
Пример #6
0
 def __call__(self, expr: E.Apply, env: E.Env) -> V.Base:
     ans_type = self.infer_type(expr)
     if not isinstance(ans_type, T.String):
         return super().__call__(expr, env)
     # TODO: return missing if either operand is missing
     ans = self.op(
         str(expr.arguments[0].eval(env).coerce(T.String()).value),
         str(expr.arguments[1].eval(env).coerce(T.String()).value),
     )
     assert isinstance(ans, str)
     return V.String(ans)
Пример #7
0
 def eval(self, env: Env.Values) -> V.String:
     ""
     ans = []
     for part in self.parts:
         if isinstance(part, Placeholder):
             # evaluate interpolated expression & stringify
             ans.append(part.eval(env).value)
         elif isinstance(part, str):
             # use python builtins to decode escape sequences
             ans.append(str.encode(part).decode("unicode_escape"))
         else:
             assert False
     # concatenate the stringified parts and trim the surrounding quotes
     return V.String("".join(ans)[1:-1])  # pyre-ignore
Пример #8
0
 def eval(self, env: Env.Values) -> V.String:
     ""
     v = self.expr.eval(env)
     if isinstance(v, V.Null):
         if "default" in self.options:
             return V.String(self.options["default"])
         return V.String("")
     if isinstance(v, V.String):
         return v
     if isinstance(v, V.Array):
         return V.String(self.options["sep"].join(
             str(item.value) for item in v.value))
     if v == V.Boolean(True) and "true" in self.options:
         return V.String(self.options["true"])
     if v == V.Boolean(False) and "false" in self.options:
         return V.String(self.options["false"])
     return V.String(str(v))
def cache_put(cfg: config.Loader, logger: logging.Logger, key: str,
              outputs: Env.Bindings[Value.Base]):
    if not (cfg["call_cache"].get_bool("put") and cfg["call_cache"]["backend"]
            == "s3_progressive_upload_call_cache_backend"):
        return

    missing = False

    def cache(v: Union[Value.File, Value.Directory]) -> str:
        nonlocal missing
        missing = missing or inode(str(v.value)) not in _uploaded_files
        if missing:
            return ""
        return _uploaded_files[inode(str(v.value))]

    remapped_outputs = Value.rewrite_env_paths(outputs, cache)
    if not missing and cfg.has_option("s3_progressive_upload", "uri_prefix"):
        uri = os.path.join(get_s3_put_prefix(cfg), "cache", f"{key}.json")
        s3_object(uri).put(
            Body=json.dumps(values_to_json(remapped_outputs)).encode())
        flag_temporary(uri)
        logger.info(_("call cache insert", cache_file=uri))
Пример #10
0
 def eval(self, env: Env.Values) -> V.Int:
     ""
     return V.Int(self.value)
Пример #11
0
 def eval(self, env: Env.Values) -> V.Boolean:
     ""
     return V.Boolean(self.value)
Пример #12
0
 def _call_eager(self, expr: E.Apply, arguments: List[V.Base]) -> V.Base:
     pfx = arguments[0].coerce(T.String()).value
     return V.Array(
         T.Array(T.String()),
         [V.String(pfx + s.coerce(T.String()).value) for s in arguments[1].value],
     )
Пример #13
0
 def _call_eager(self, expr: E.Apply, arguments: List[V.Base]) -> V.Base:
     arg0 = arguments[0]
     assert isinstance(arg0, V.Int)
     if arg0.value < 0:
         raise Error.EvalError(expr, "range() got negative argument")
     return V.Array(T.Array(T.Int()), [V.Int(x) for x in range(arg0.value)])
Пример #14
0
 def __call__(self, expr: E.Apply, env: Env.Values) -> V.Base:
     v = expr.arguments[0].eval(env)
     if isinstance(v, V.Null):
         return V.Int(0)
     assert isinstance(v.value, list)
     return V.Int(len(v.value))
Пример #15
0
 def eval(self, env: Env.Values) -> V.Base:
     ""
     assert isinstance(self.type, T.Pair)
     lv = self.left.eval(env)
     rv = self.right.eval(env)
     return V.Pair(self.type, (lv, rv))
Пример #16
0
 def __call__(self, expr: E.Apply, env: Env.Values, stdlib: Base) -> V.Base:
     lhs = expr.arguments[0].eval(env, stdlib=stdlib).expect(T.Boolean()).value
     if lhs:
         return V.Boolean(True)
     return expr.arguments[1].eval(env, stdlib=stdlib).expect(T.Boolean())
Пример #17
0
    def __init__(self):
        # language built-ins
        self._at = _At()
        self._land = _And()
        self._lor = _Or()
        self._negate = StaticFunction(
            "_negate", [T.Boolean()], T.Boolean(), lambda x: V.Boolean(not x.value)
        )
        self._add = _AddOperator()
        self._sub = _ArithmeticOperator("-", lambda l, r: l - r)
        self._mul = _ArithmeticOperator("*", lambda l, r: l * r)
        self._div = _ArithmeticOperator("/", lambda l, r: l // r)
        self._rem = StaticFunction(
            "_rem", [T.Int(), T.Int()], T.Int(), lambda l, r: V.Int(l.value % r.value)
        )
        self._eqeq = _ComparisonOperator("==", lambda l, r: l == r)
        self._neq = _ComparisonOperator("!=", lambda l, r: l != r)
        self._lt = _ComparisonOperator("<", lambda l, r: l < r)
        self._lte = _ComparisonOperator("<=", lambda l, r: l <= r)
        self._gt = _ComparisonOperator(">", lambda l, r: l > r)
        self._gte = _ComparisonOperator(">=", lambda l, r: l >= r)

        # static stdlib functions
        for (name, argument_types, return_type, F) in [
            ("floor", [T.Float()], T.Int(), lambda v: V.Int(math.floor(v.value))),
            ("ceil", [T.Float()], T.Int(), lambda v: V.Int(math.ceil(v.value))),
            ("round", [T.Float()], T.Int(), lambda v: V.Int(round(v.value))),
            ("length", [T.Array(T.Any())], T.Int(), lambda v: V.Int(len(v.value))),
            ("sub", [T.String(), T.String(), T.String()], T.String(), _sub),
            ("basename", [T.String(), T.String(optional=True)], T.String(), _basename),
            (
                "defined",
                [T.Any(optional=True)],
                T.Boolean(),
                lambda v: V.Boolean(not isinstance(v, V.Null)),
            ),
            # context-dependent:
            ("write_lines", [T.Array(T.String())], T.File(), _notimpl),
            ("write_tsv", [T.Array(T.Array(T.String()))], T.File(), _notimpl),
            ("write_map", [T.Map((T.Any(), T.Any()))], T.File(), _notimpl),
            ("write_json", [T.Any()], T.File(), _notimpl),
            ("stdout", [], T.File(), _notimpl),
            ("stderr", [], T.File(), _notimpl),
            ("glob", [T.String()], T.Array(T.File()), _notimpl),
            ("read_int", [T.File()], T.Int(), _notimpl),
            ("read_boolean", [T.File()], T.Boolean(), _notimpl),
            ("read_string", [T.File()], T.String(), _notimpl),
            ("read_float", [T.File()], T.Float(), _notimpl),
            ("read_array", [T.File()], T.Array(T.Any()), _notimpl),
            ("read_map", [T.File()], T.Map((T.Any(), T.Any())), _notimpl),
            ("read_lines", [T.File()], T.Array(T.Any()), _notimpl),
            ("read_tsv", [T.File()], T.Array(T.Array(T.String())), _notimpl),
            ("read_json", [T.File()], T.Any(), _notimpl),
        ]:
            setattr(self, name, StaticFunction(name, argument_types, return_type, F))

        # polymorphically typed stdlib functions which require specialized
        # infer_type logic
        self.range = _Range()
        self.prefix = _Prefix()
        self.size = _Size()
        self.select_first = _SelectFirst()
        self.select_all = _SelectAll()
        self.zip = _Zip()
        self.cross = _Zip()  # FIXME
        self.flatten = _Flatten()
        self.transpose = _Transpose()
Пример #18
0
def _sub(input: V.String, pattern: V.String, replace: V.String) -> V.String:
    return V.String(re.compile(pattern.value).sub(replace.value, input.value))
Пример #19
0
 def __call__(self, expr: E.Apply, env: E.Env) -> V.Base:
     assert len(expr.arguments) == 2
     return V.Boolean(
         # pyre-fixme
         self.op(expr.arguments[0].eval(env).value,
                 expr.arguments[1].eval(env).value))
Пример #20
0
 def eval(self, env: Env.Values) -> V.Float:
     ""
     return V.Float(self.value)
Пример #21
0
 def __call__(self, expr: E.Apply, env: E.Env) -> V.Base:
     lhs = expr.arguments[0].eval(env).expect(T.Boolean()).value
     if lhs:
         return V.Boolean(True)
     return expr.arguments[1].eval(env).expect(T.Boolean())
Пример #22
0
 def _call_eager(self, expr: E.Apply, arguments: List[V.Base]) -> V.Base:
     assert len(arguments) == 2
     return V.Boolean(self.op(arguments[0].value, arguments[1].value))
Пример #23
0
 def eval(self, env: Env.Values) -> V.Array:
     ""
     assert isinstance(self.type, T.Array)
     return V.Array(self.type, [
         item.eval(env).coerce(self.type.item_type) for item in self.items
     ])
Пример #24
0
 def _call_eager(self, expr: E.Apply, arguments: List[V.Base]) -> V.Base:
     arr = arguments[0]
     assert isinstance(arr, V.Array)
     arrty = arr.type
     assert isinstance(arrty, T.Array)
     return V.Array(arrty, [arg for arg in arr.value if not isinstance(arg, V.Null)])
Пример #25
0
        assert len(expr.arguments) == len(self.argument_types)
        argument_values = [
            arg.eval(env).coerce(ty)
            for arg, ty in zip(expr.arguments, self.argument_types)
        ]
        ans: V.Base = self.F(*argument_values)
        return ans.coerce(self.return_type)


def _notimpl(one: Any = None, two: Any = None) -> None:
    exec("raise NotImplementedError()")


_static_functions: List[Tuple[str, List[T.Base], T.Base, Any]] = [
    ("_negate", [T.Boolean()], T.Boolean(),
     lambda x: V.Boolean(not x.value)),  # pyre-fixme
    ("_rem", [T.Int(), T.Int()], T.Int(),
     lambda l, r: V.Int(l.value % r.value)),  # pyre-fixme
    ("stdout", [], T.File(), _notimpl),
    ("basename", [T.String(), T.String(optional=True)], T.String(), _notimpl),
    # note: size() can take an empty value and probably returns 0 in that case.
    #       e.g. https://github.com/DataBiosphere/topmed-workflows/blob/31ba8a714b36ada929044f2ba3d130936e6c740e/CRAM-no-header-md5sum/md5sum/CRAM_md5sum.wdl#L39
    ("size", [T.File(optional=True),
              T.String(optional=True)], T.Float(), _notimpl),
    ("ceil", [T.Float()], T.Int(), _notimpl),
    ("round", [T.Float()], T.Int(), _notimpl),
    ("glob", [T.String()], T.Array(T.File()), _notimpl),
    ("read_int", [T.String()], T.Int(), _notimpl),
    ("read_boolean", [T.String()], T.Boolean(), _notimpl),
    ("read_string", [T.String()], T.String(), _notimpl),
    ("read_float", [T.String()], T.Float(), _notimpl),
Пример #26
0
 def __call__(self, expr: E.Apply, env: Env.Values) -> V.Base:
     if isinstance(expr.arguments[0].eval(env), V.Null):
         return V.Boolean(False)
     return V.Boolean(True)