예제 #1
0
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
예제 #2
0
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
예제 #3
0
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)'
예제 #4
0
    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
예제 #5
0
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)
예제 #6
0
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'
예제 #7
0
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
예제 #8
0
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
예제 #9
0
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'
예제 #10
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)
예제 #11
0
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
예제 #12
0
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)
예제 #13
0
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)