Skip to content

Commit

Permalink
Merge pull request #5 from magniff/feature/toggle
Browse files Browse the repository at this point in the history
Feature/toggle
  • Loading branch information
Aleksandr Koshkin committed Sep 28, 2018
2 parents 694e428 + d0a4706 commit c4a976c
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 85 deletions.
44 changes: 44 additions & 0 deletions benchmarks/overhead.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import perf


from watch.builtins import InstanceOf, Container, Mapping
from watch import WatchMe


class MyClass(WatchMe):
value = Container(InstanceOf(str) >> InstanceOf(int))


class MyClassNoWatch:
pass


controlled_instance = MyClass()
simple_instance = MyClassNoWatch()


value = [{'a': 1, 'b': 2, 'c': 3, 'd': 4}]


def bench_set():
controlled_instance.value = value


def pivot_bench_set():
simple_instance.value = value


runner = perf.Runner()


# Check with validation enabled
WatchMe.is_active = True
runner.bench_func("set: validation enabled", bench_set)

# Check with validation disabled
WatchMe.is_active = False
runner.bench_func("set: validation disabled", bench_set)

# Check with a plain type with no watch at all
runner.bench_func("set: no watch at all", pivot_bench_set)

39 changes: 0 additions & 39 deletions benchmarks/simple.py

This file was deleted.

119 changes: 100 additions & 19 deletions tests/test_validators.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from collections.abc import Iterable
from numbers import Number
from itertools import chain


import py.test


from watch import WatchMe, Predicate
from watch.builtins import (
Not, Or, And, Xor, Whatever, Container, InstanceOf, Mapping, Just,
GtThen, LtThen, Nullable
Not, Or, And, Xor, Whatever, Nothing, Container, InstanceOf, SubclassOf,
Mapping, Just, GtThen, LtThen, LtEqThen, GtEqThen, Nullable
)


Expand Down Expand Up @@ -40,6 +42,16 @@
(6.0, True),
]
),
# Greater or Equal
(
GtEqThen(5),
[
(4, False),
(5, True),
(6, True),
(6.0, True),
]
),
# Lesser
(
LtThen(5),
Expand All @@ -50,6 +62,16 @@
(4.0, True),
]
),
# Lesser or Equal
(
LtEqThen(5),
[
(10, False),
(5, True),
(4, True),
(4.0, True),
]
),
# InstanceOf(int)
(
InstanceOf(int),
Expand All @@ -61,6 +83,17 @@
(False, True),
]
),
# InstanceOf(int, str)
(
InstanceOf(int, str),
[
(10, True),
(1.1, False),
("helloworld", True),
(True, True),
(False, True),
]
),
# simple predicate
(
Predicate(lambda value: value > 0),
Expand Down Expand Up @@ -169,6 +202,7 @@
),
]


MAGIC_CASES = [
# Not
(
Expand All @@ -195,6 +229,16 @@
(0, False),
]
),
# multiple XOR operands are not allowed to be True at the same time
# meaning that value does not belong to corresponding set intersection
(
InstanceOf(int) & (GtThen(10) ^ LtThen(20)),
[
(1, True),
(30, True),
(15, False),
]
),
# OR(Just)
(
Just(5) | Just(6),
Expand All @@ -204,7 +248,7 @@
(5, True),
]
),
# OR(Just | Whatever): should falldback to Whatever
# OR(Just, Whatever): should falldback to Whatever
(
Just(5) | Just(6) | Whatever,
[
Expand All @@ -213,6 +257,15 @@
("hello", True),
]
),
# And(Just, Nothing): should falldback to Nothing
(
(Just(5) | Just(6)) & Nothing,
[
(6, False),
(5, False),
("hello", False),
]
),
# Greater
(
InstanceOf(int) < 100,
Expand All @@ -224,6 +277,16 @@
(0, True),
]
),
# Ints > 0 but not 100
(
(InstanceOf(int) > 0) & ~Just(100),
[
(10, True),
(90, True),
(200, True),
(100, False),
]
),
# Mapping + Just
(
Mapping(
Expand All @@ -244,9 +307,8 @@
),
# This is the same Mapping + Just case, yet even more magical
(
InstanceOf(int) >> (Just(True) | Just(False)),
# Just also supports multiple values as initializer:
# InstanceOf(int) >> Just(True, False)
InstanceOf(int) >> Just(True, False),
# or simply InstanceOf(int) >> InstanceOf(bool)
[
(
# sanity check
Expand All @@ -262,7 +324,7 @@
),
]
),
# Container of ints + GT/LT
# Container of ints or just a "hello" + GT/LT
(
Container(
items=(
Expand Down Expand Up @@ -293,8 +355,12 @@
),
[
("hello", False),
({value: str(value) for value in range(1, 10)}, False),
({value: str(value) for value in range(-10, 0)}, False),
(
{value: str(value) for value in range(1, 10)}, False
),
(
{value: str(value) for value in range(-10, 0)}, False
),
(
{
1: {"hello": True},
Expand All @@ -307,12 +373,34 @@
),
]
),
# SubclassOf(Number) but not bool
(
SubclassOf(Number) & ~Just(bool),
[
(int, True),
(float, True),
(complex, True),
(str, False),
(bool, False),
]
),
# Similar to the prev one, but using Xor
(
SubclassOf(Number) ^ Just(bool) ^ Just(int),
[
(int, False),
(float, True),
(complex, True),
(str, False),
(bool, False),
]
),
]


def cases(case_spec):
def cases(*cases):

for case in case_spec:
for case in chain(*cases):
validator, examples = case
for (test_value, test_result) in examples:
yield (validator, test_value, test_result)
Expand All @@ -321,15 +409,8 @@ def cases(case_spec):


@py.test.mark.parametrize(
"validator,value_to_test,expected_result", cases(CASES)
"validator,value_to_test,expected_result", cases(CASES, MAGIC_CASES)
)
def test_validators(validator, value_to_test, expected_result):
assert validator().predicate(value_to_test) == expected_result


@py.test.mark.parametrize(
"validator,value_to_test,expected_result", cases(MAGIC_CASES)
)
def test_magics(validator, value_to_test, expected_result):
assert validator().predicate(value_to_test) == expected_result

61 changes: 61 additions & 0 deletions tests/test_watch_disable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import py.test
import watch


def test_toggle_scenario_for_types():

class A(watch.WatchMe):
foo = watch.builtins.InstanceOf(int)

class B(watch.WatchMe):
foo = watch.builtins.InstanceOf(int)

a = A()
b = B()

# default scenario for a
with py.test.raises(AttributeError):
a.foo = "hello"

# default scenario for b
with py.test.raises(AttributeError):
b.foo = "hello"

A.is_active = False
a.foo = "hello"
assert a.foo == "hello"

# disabling watch for A has nothing to do with B
with py.test.raises(AttributeError):
b.foo = "hello"

# now watch is disabled globaly
watch.WatchMe.is_active = False

a.foo = "hello"
assert a.foo == "hello"

b.foo = "hello"
assert b.foo == "hello"

watch.WatchMe.is_active = True


def test_toggle_scenario_for_instances():

class A(watch.WatchMe):
foo = watch.builtins.InstanceOf(int)

a = A()
b = A()

a.is_active = False
a.foo = "hello"
assert a.foo == "hello"

# default scenario for b
with py.test.raises(AttributeError):
b.foo = "hello"

watch.WatchMe.is_active = True

0 comments on commit c4a976c

Please sign in to comment.