class OutputSpec(object): def __init__(self, name: str, data_type: Any, nullable: bool, metadata: Any = None): self.name = assert_triad_var_name(name) self.data_type = to_type(data_type) self.nullable = nullable self.metadata = ParamDict(metadata, deep=True) self.metadata.set_readonly() def __uuid__(self) -> str: return to_uuid([self.__dict__[x] for x in self.attributes]) def __repr__(self) -> str: return self.name def validate_value(self, obj: Any) -> Any: if obj is not None: aot( isinstance(obj, self.data_type), lambda: TypeError(f"{obj} mismatches type {self.paramdict}"), ) return obj aot(self.nullable, lambda: f"Can't set None to {self}") return obj def validate_spec(self, spec: "OutputSpec") -> "OutputSpec": if not self.nullable: aot( not spec.nullable, lambda: TypeError( f"{self} - {spec} are not compatible on nullable"), ) aot( issubclass(spec.data_type, self.data_type), lambda: TypeError( f"{self} - {spec} are not compatible on data_type"), ) return spec @property def attributes(self) -> List[str]: return ["name", "data_type", "nullable", "metadata"] @property def paramdict(self) -> ParamDict: return ParamDict((x, self.__dict__[x]) for x in self.attributes) @property def jsondict(self) -> ParamDict: res = ParamDict() for k, v in self.paramdict.items(): if isinstance(v, type): v = get_full_type_path(v) res[k] = v return res
def test_param_dict(): d = ParamDict([("a", 1), ("b", 2)]) assert 1 == d["a"] assert 1 == d[0] assert 2 == d["b"] assert "2" == d.get_or_throw(1, str) # if giving index, it should ignore the throw flag and always throw raises(IndexError, lambda: d.get(2, "x")) raises(IndexError, lambda: d.get_or_none(2, str)) d = {"a": "b", "b": {"x": 1, "y": "d"}} p = ParamDict(d) print({"test": p}) d["b"]["x"] = 2 assert 1 == p["b"]["x"] p = ParamDict(d, deep=False) d["b"]["x"] = 3 assert 3 == p["b"]["x"] pp = ParamDict(p, deep=False) p["b"]["x"] = 4 assert 4 == pp["b"]["x"] pp = ParamDict(p, deep=True) p["b"]["x"] = 5 assert 4 == pp["b"]["x"] assert 2 == len(p) assert "a,b" == ",".join([k for k, _ in p.items()]) del p["a"] assert 1 == len(p) p["c"] = 1 assert 2 == len(p) assert "c" in p assert "a" not in p raises(ValueError, lambda: p.get("c", None)) assert 1 == p.get("c", 2) assert "1" == p.get("c", "2") assert 1.0 == p.get("c", 2.0) raises(TypeError, lambda: p.get("c", ParamDict())) assert 2 == p.get("d", 2) p["arr"] = [1, 2] assert [1, 2] == p.get("arr", []) assert [] == p.get("arr2", []) assert p.get_or_none("e", int) is None assert 1 == p.get_or_none("c", int) assert "1" == p.get_or_none("c", str) # exists but can't convert type raises(TypeError, lambda: p.get_or_none("c", ParamDict)) raises(KeyError, lambda: p.get_or_throw("e", int)) assert 1 == p.get_or_throw("c", int) assert "1" == p.get_or_throw("c", str) # exists but can't convert type raises(TypeError, lambda: p.get_or_throw("c", ParamDict)) p = ParamDict() assert 0 == len(p) for x in p: pass raises(TypeError, lambda: ParamDict("abc")) a = ParamDict({"a": 1, "b": 2}) b = ParamDict({"b": 2, "a": 1}) c = ParamDict({"b": 2}) assert a == a assert a != b assert a != c assert a == {"b": 2, "a": 1} assert a != {"b": 1, "a": 1} assert a != None assert not (a == None) p = ParamDict({ "a": "True", "b": True, "c": "true", "d": "False", "e": False, "f": "false", "g": "yes", "h": "NO", "i": 0, "j": "1", "k": "", }) assert p.get_or_throw("a", bool) assert p.get_or_throw("b", bool) assert p.get_or_throw("c", bool) assert not p.get_or_throw("d", bool) assert not p.get_or_throw("e", bool) assert not p.get_or_throw("f", bool) assert p.get_or_throw("g", bool) assert not p.get_or_throw("h", bool) assert not p.get_or_throw("i", bool) assert p.get_or_throw("j", bool) raises(TypeError, lambda: p.get_or_throw("k", bool)) s = '{"a":false,"b":10,"c":"cd"}' p = ParamDict(json.loads(s)) assert not p.get_or_throw("a", bool) assert "10" == p.get_or_throw("b", str) assert "cd" == p.get_or_throw("c", str) raises(KeyError, lambda: p.get_or_throw("d", str)) print(p.to_json()) print(p.to_json(True)) # update p = ParamDict(dict(a=1, b=2)) p1 = ParamDict(dict(b=3, c=4)) p.update(p1) assert dict(a=1, b=3, c=4) == p p = ParamDict(dict(a=1, b=2)) p.update(p1, ParamDict.OVERWRITE) assert dict(a=1, b=3, c=4) == p p = ParamDict(dict(a=1, b=2)) p.update(p1, ParamDict.IGNORE) assert dict(a=1, b=2, c=4) == p p = ParamDict(dict(a=1, b=2)) raises(KeyError, lambda: p.update(p1, ParamDict.THROW)) raises(ValueError, lambda: p.update(p1, 100)) p.set_readonly() raises(InvalidOperationError, lambda: p.update(p1, 100))