def test_context_local_codec(): class X(meta.Entity): a = meta.Integer(codec='test') class TestCodec(meta.Codec): def encode(self, value, property, context): return -value def decode(self, value, property, context): return -value ctx = meta.Context() ctx.set_codec('test', TestCodec()) x = X() x.a = 123 assert x.dump(ctx) == {'a': -123} x = X().load({'a': 789}, ctx) assert x.a == -789 with pytest.raises(LookupError): x.dump(meta.Context()) ctx.set_codec('test', TestCodec()) x = X() x.a = 123 assert x.dump(ctx) == {'a': -123} x = X().load({'a': 789}, ctx) assert x.a == -789
def test_error(): @meta.declare class X: pass class X(meta.Entity): x = X(required=True) d = dict(x=dict(x=1)) context = meta.Context() with pytest.raises(ValueError): X().load(d, context) assert context.errors is not None assert len(context.errors) == 1 assert context.errors[0].value == 1 assert context.errors[0].location == '/x/x' assert context.errors[0].exc_info[0] == ValueError @meta.declare class Child: pass class Parent(meta.Entity): children = Child[:](required=True) class Child(meta.Entity): parent = Parent(required=True) d = dict(children=[ dict(parent={}, ), dict(parent=dict(children=[dict(parent=None)])) ], ) context = meta.Context() with pytest.raises(ValueError): Parent().load(d, context) assert context.errors[0].value == None assert context.errors[0].location == '/children/1/parent/children/0/parent' assert context.errors[0].exc_info[0] == ValueError d = dict(children=[ dict(parent={}, ), dict(parent=dict(children=[dict(father=None)])) ], ) context = meta.Context(strict=True) with pytest.raises(ValueError): Parent().load(d, context) assert context.errors[0].value is meta.Null assert context.errors[0].location == '/children/1/parent/children/0/father' assert context.errors[0].exc_info[0] == ValueError context.reset() with pytest.raises(ValueError): Parent().load([], context) print(context._errtree) assert context.errors is not None assert context.errors[0].value == [] assert context.errors[0].location == '' assert context.errors[0].exc_info[0] == ValueError
def test_context(): assert repr(meta.Context()) == 'Context()' ctx = meta.Context(strict=True) with pytest.raises(ValueError): x = meta.Entity().load({'x': 1}, ctx) assert repr(ctx) == 'Context(errors=[ValueError(/x?)], strict=True)'
def __init__(self, root=None): if root is None or hasattr(self, '_root'): return self._root = App._norm_root(root) try: if not os.path.exists(os.path.join(self._root, self.appfile())): raise AppfileNotFoundError() with open(os.path.join(self._root, self.appfile()), 'rb') as f: data = yaml.safe_load(f) or {} # # two-phase configuration loading # # first phase # 기본 설정만 로딩한 후 플러그인들을 임포트한다. App._loading = True try: for modname in self.builtins(): importlib.import_module(modname) finally: App._loading = False context = meta.Context() try: self._config = self.Config().load(data, context) self._config.validate() except ValueError: raise AppfileError(context) App._loading = True try: for modname in (self._config.plugins or []): importlib.import_module(modname) finally: App._loading = False # second phase # 플러그인들의 설정을 반영해서 최종 로딩한다. CustomConfig = self.Config.define_subclass('Config', _defines) context = meta.Context() try: self._config = CustomConfig().load(data, context) self._config.validate() except ValueError: raise AppfileError(context) for hook in App._on_loads: hook(self) except: App._instance = None raise
def test_is_visible(): class X(meta.Entity): a = meta.Integer(required=True) b = meta.Integer() c = meta.Integer(view='private') public = meta.Context(view='public') private = meta.Context(view='private') x = X() assert x.is_visible('a', None) assert x.is_visible('b', None) assert x.is_visible('c', None) assert not x.is_visible('d', None) assert x.is_visible('a', public) assert x.is_visible('b', public) assert not x.is_visible('c', public) assert x.is_visible('a', private) assert x.is_visible('b', private) assert x.is_visible('c', private) for x in (X(only='b'), X(only=['b']), X(only={'b'})): assert x.is_visible('a', None) assert x.is_visible('b', None) assert not x.is_visible('c', None) assert x.is_visible('a', public) assert x.is_visible('b', public) assert not x.is_visible('c', public) assert x.is_visible('a', private) assert x.is_visible('b', private) assert not x.is_visible('c', private) for x in (X(only='c'), X(only=['c']), X(only={'c'})): assert x.is_visible('a', None) assert not x.is_visible('b', None) assert x.is_visible('c', None) assert x.is_visible('a', public) assert not x.is_visible('b', public) assert not x.is_visible('c', public) assert x.is_visible('a', private) assert not x.is_visible('b', private) assert x.is_visible('c', private)
def test_marker(): context = meta.Context() value = { 'a': [1, 2, 3], 'b': [5, { 'x': 1234, }] } def travel(value, context): if value == 1234: raise ValueError() with Marker(context, value) as marker: if isinstance(value, dict): for k, v in value.items(): with marker.cursor(k, v): travel(v, marker.context) elif isinstance(value, (tuple, list)): for i, v in enumerate(value): with marker.cursor(i, v): travel(v, marker.context) with pytest.raises(ValueError): travel(value, context) assert context.errors is not None assert context.errors[0].value == 1234 assert context.errors[0].location == '/b/1/x'
def test_toplevel_errors(): class X(meta.Entity): a = meta.Integer[:]() context = meta.Context(strict=True, max_errors=10) with pytest.raises(ValueError): X(required=True).load(None, context) assert len(context.errors) == 1 assert context.errors[0].location == '' assert context.errors[0].value == None assert context.errors[0].exc_info[0] == ValueError
def test_json_codec(): class X(meta.Entity): a = meta.JsonObject() b = meta.JsonObject(codec=[meta.codec('json')]) x = X() data = OrderedDict({'x': 1, 'y': []}) x.a = x.b = data assert x.dump() == {'a': data, 'b': data} assert x.dump(meta.Context()) == { 'a': data, 'b': json.dumps(data, ensure_ascii=False, separators=(',', ':')) } x = X(codec='json') x.a = data assert x.dump() == {'a': data} assert x.dump(meta.Context()) == json.dumps({'a': data}, ensure_ascii=False, separators=(',', ':')) x = X().load({'a': data, 'b': json.dumps(data)}, meta.Context()) assert x.a == data assert x.b == data
def test_union_with_error(): class U(meta.Union): s = meta.Integer(ordered=True) m = meta.String(ordered=True) class X(meta.Entity): a = meta.Tuple(meta.Integer(), U()) ctx = meta.Context(max_errors=10) with pytest.raises(ValueError): x = X().load({'a': ['abc', 'xyz']}, ctx) print(ctx.errors) assert len(ctx.errors) == 1 assert ctx.errors[0].location == '/a/0'
def test_view_in_tuple(): class X(meta.Entity): p = meta.Tuple(meta.Integer(), meta.String(view='secret')) x = X() x.p = (1, 'secret') assert x.p == (1, 'secret') ctx = meta.Context(view='nobody') assert x.dump(ctx) == {'p': [1, None]} x = X().load({'p': [1, None]}, ctx) assert x.p == (1, None) with pytest.raises(ValueError): X().load({'p': [1, 'secret']}, ctx)
def test_multi_errors(): @meta.declare class Child: pass class Parent(meta.Entity): children = Child[:](required=True) class Child(meta.Entity): parent = Parent(required=True) d = dict( children=[ 1, # error dict( parent=None, # error ), dict(parent=dict(children=[ dict( father=None, # error ), ])), 'abc', # error ], ) context = meta.Context(strict=True, max_errors=3) with pytest.raises(ValueError): Parent().load(d, context) assert len(context.errors) == 3 assert context.errors[0].location == '/children/0' assert context.errors[0].value == 1 assert context.errors[0].exc_info[0] == ValueError assert context.errors[1].location == '/children/1/parent' assert context.errors[1].value is None assert context.errors[1].exc_info[0] == ValueError assert context.errors[2].location == '/children/2/parent/children/0/father' assert context.errors[2].value is meta.Null assert context.errors[2].exc_info[0] == ValueError
def test_date(): class X(meta.Entity): p = meta.Date(format='unix') success = [datetime.datetime.now(), datetime.datetime.now().date(), time.time(), 0, 0.0] failure = [datetime.time(), '한', u'한', b'\xed\x95\x9c', [1], (1,), ['a'], ('b',), entity] x = X() for value in success: x.p = value assert isinstance(x.p, datetime.date) x.validate() for value in failure: with pytest.raises(ValueError): x.p = value print(value) timestamp = 1457276664.038691 utc_naive = datetime.datetime(2016, 3, 6, 15, 4, 24, 38691) kst_naive = datetime.datetime(2016, 3, 7, 0, 4, 24, 38691) utc_aware = utc_naive.replace(tzinfo=timezone.utc) kst_aware = kst_naive.replace(tzinfo=timezone(datetime.timedelta(hours=9))) sod = timestamp - (15 * 3600 + 4 * 60 + 24.038691) utc_date = datetime.date(2016, 3, 6) kst_date = datetime.date(2016, 3, 7) assert X.p.dump(utc_date) == sod assert utc_date == X.p.load(timestamp) assert utc_date == X.p.load(sod) x.p = timestamp assert x.p == utc_date x.p = utc_aware assert x.p == utc_date x.p = kst_aware assert x.p == kst_date x.p = utc_naive assert x.p == utc_date x.p = kst_date assert x.p == kst_date x.p = utc_date assert x.p == utc_date # # iso8601 # class X(meta.Entity): p = meta.Date() date_iso8601 = '2016-03-06' utc_iso8601 = '2016-03-06T15:04:24.038691Z' kst_iso8601 = '2016-03-07T00:04:24.038691+09:00' context = meta.Context() assert X.p.dump(utc_naive.date(), context) == date_iso8601 assert X.p.dump(utc_aware.date(), context) == date_iso8601 assert utc_date == X.p.load(date_iso8601, context) assert utc_date == X.p.load(utc_iso8601, context) assert kst_date == X.p.load(kst_iso8601, context)
def test_time(): class X(meta.Entity): p = meta.Time(format='unix') success = [datetime.datetime.now(), datetime.datetime.now().time(), datetime.time(), time.time(), 0, 0.0] failure = [datetime.date(1999, 1, 1), '한', u'한', b'\xed\x95\x9c', [1], (1,), ['a'], ('b',), entity] x = X() for value in success: x.p = value assert isinstance(x.p, datetime.time) x.validate() for value in failure: with pytest.raises(ValueError): x.p = value print(value) timestamp = 1457276664.038691 utc_naive = datetime.datetime(2016, 3, 6, 15, 4, 24, 38691).time() kst_naive = datetime.datetime(2016, 3, 7, 0, 4, 24, 38691).time() utc_aware = utc_naive.replace(tzinfo=timezone.utc) kst_aware = kst_naive.replace(tzinfo=timezone(datetime.timedelta(hours=9))) tod = 15 * 3600 + 4 * 60 + 24.038691 assert X.p.dump(utc_naive) == tod assert X.p.dump(utc_aware) == tod assert X.p.dump(kst_aware) == tod assert X.p.load(timestamp).tzinfo is timezone.utc assert utc_aware == X.p.load(timestamp) assert X.p.load(tod).tzinfo is timezone.utc assert utc_aware == X.p.load(tod) for value in (timestamp, tod): x.p = value assert x.p == utc_aware x.p = utc_aware assert x.p == utc_aware x.p = kst_aware assert x.p == kst_aware x.p = utc_naive assert x.p == utc_naive # # iso8601 # class X(meta.Entity): p = meta.Time() naive_iso8601 = '15:04:24.038691' utc_iso8601 = '15:04:24.038691Z' kst_iso8601 = '00:04:24.038691+09:00' context = meta.Context() assert X.p.dump(utc_naive, context) == naive_iso8601 assert X.p.dump(utc_aware, context) == utc_iso8601 assert X.p.dump(kst_aware, context) == kst_iso8601 assert X.p.load(utc_iso8601, context).tzinfo is timezone.utc assert utc_aware == X.p.load(utc_iso8601, context) assert X.p.load(kst_iso8601, context).utcoffset() == datetime.timedelta(hours=9) assert kst_aware == X.p.load(kst_iso8601, context)