def test_typed_value() -> None: val = TypedValue(str) assert_is(str, val.typ) assert_eq("str", str(val)) assert val.is_type(str) assert not val.is_type(int) assert_can_assign(val, val) assert_cannot_assign(val, TypedValue(int)) assert_can_assign(val, KnownValue("x")) assert_can_assign(val, MultiValuedValue([val, KnownValue("x")])) assert_cannot_assign(val, MultiValuedValue([KnownValue("x"), TypedValue(int)])) float_val = TypedValue(float) assert_eq("float", str(float_val)) assert_can_assign(float_val, KnownValue(1.0)) assert_can_assign(float_val, KnownValue(1)) assert_cannot_assign(float_val, KnownValue("")) assert_can_assign(float_val, TypedValue(float)) assert_can_assign(float_val, TypedValue(int)) assert_cannot_assign(float_val, TypedValue(str)) assert_can_assign(float_val, TypedValue(mock.Mock)) assert_cannot_assign(float_val, SubclassValue(TypedValue(float))) assert_can_assign(TypedValue(type), SubclassValue(TypedValue(float)))
def test_cached_per_instance_pickling(): # make sure cached stuff doesn't appear in the pickled representation obj = PickleTestClass() obj.attr = 'spam' assert_is(False, hasattr(obj, '__lib_cache')) obj.f('my hovercraft is full of eels') assert_eq(1, len(obj.__lib_cache)) serialized = pickle.dumps(obj) assert_not_in(b'my hovercraft is full of eels', serialized) assert_in(b'spam', serialized) restored = pickle.loads(serialized) assert_is(False, hasattr(restored, '__lib_cache')) restored.f('my hovercraft is full of eels') assert_eq(1, len(restored.__lib_cache)) assert_eq('spam', obj.attr) # make sure we can't use this with a custom __getstate__ with AssertRaises(AssertionError): class X(object): @cached_per_instance() def f(self, x): return x def __getstate__(self): return {} X().f(1)
def test_referencing_value(self): with self.scopes.add_scope(ScopeType.module_scope, scope_node=None): outer = self.scopes.current_scope() self.scopes.set("reference", KnownValue(1), None, None) multivalue = MultiValuedValue([KnownValue(1), KnownValue(2)]) with self.scopes.add_scope(ScopeType.module_scope, scope_node=None): val = ReferencingValue(outer, "reference") self.scopes.set("reference", val, None, None) assert_eq(KnownValue(1), self.scopes.get("reference", None, None)) self.scopes.set("reference", KnownValue(2), None, None) assert_eq(multivalue, self.scopes.get("reference", None, None)) assert_eq(multivalue, self.scopes.get("reference", None, None)) self.scopes.set( "nonexistent", ReferencingValue(self.scopes.module_scope(), "nonexistent"), None, None, ) assert_is(UNINITIALIZED_VALUE, self.scopes.get("nonexistent", None, None)) self.scopes.set("is_none", KnownValue(None), None, None) with self.scopes.add_scope(ScopeType.function_scope, scope_node=None): self.scopes.set( "is_none", ReferencingValue(outer, "is_none"), None, None ) assert_is(UNRESOLVED_VALUE, self.scopes.get("is_none", None, None))
def test_set(self): with self.scopes.add_scope(ScopeType.module_scope, scope_node=None): self.scopes.set("multivalue", KnownValue(1), None, None) assert_eq(KnownValue(1), self.scopes.get("multivalue", None, None)) self.scopes.set("multivalue", KnownValue(2), None, None) assert_eq( MultiValuedValue([KnownValue(1), KnownValue(2)]), self.scopes.get("multivalue", None, None), ) self.scopes.set("multivalue", KnownValue(3), None, None) assert_eq( MultiValuedValue([KnownValue(1), KnownValue(2), KnownValue(3)]), self.scopes.get("multivalue", None, None), ) # if the values set are the same, don't make a MultiValuedValue self.scopes.set("same", KnownValue(1), None, None) assert_eq(KnownValue(1), self.scopes.get("same", None, None)) self.scopes.set("same", KnownValue(1), None, None) assert_eq(KnownValue(1), self.scopes.get("same", None, None)) # even if they are UNRESOLVED_VALUE self.scopes.set("unresolved", UNRESOLVED_VALUE, None, None) assert_is(UNRESOLVED_VALUE, self.scopes.get("unresolved", None, None)) self.scopes.set("unresolved", UNRESOLVED_VALUE, None, None) assert_is(UNRESOLVED_VALUE, self.scopes.get("unresolved", None, None))
def test_typed_value(): val = TypedValue(str) assert_is(str, val.typ) assert_eq("str", str(val)) assert val.is_type(str) assert not val.is_type(int) assert val.is_value_compatible(TypedValue(str)) assert not val.is_value_compatible(TypedValue(int)) assert val.is_value_compatible( MultiValuedValue([KnownValue("x"), TypedValue(str)])) assert not val.is_value_compatible( MultiValuedValue([KnownValue("x"), TypedValue(int)])) float_val = TypedValue(float) assert_eq("float", str(float_val)) assert float_val.is_value_compatible(KnownValue(1.0)) assert float_val.is_value_compatible(KnownValue(1)) assert not float_val.is_value_compatible(KnownValue("")) assert float_val.is_value_compatible(TypedValue(float)) assert float_val.is_value_compatible(TypedValue(int)) assert not float_val.is_value_compatible(TypedValue(str)) assert float_val.is_value_compatible(TypedValue(value.mock.Mock)) assert not float_val.is_value_compatible(SubclassValue(float)) assert TypedValue(type).is_value_compatible(SubclassValue(float))
def test_get(self): assert_eq(KnownValue(1), self.scope.get("foo", None, None)) with self.scope.add_scope(ScopeType.module_scope, scope_node=None): self.scope.set("foo", KnownValue(2), None, None) assert_eq(KnownValue(2), self.scope.get("foo", None, None)) assert_eq(KnownValue(1), self.scope.get("foo", None, None)) assert_is(UNINITIALIZED_VALUE, self.scope.get("doesnt_exist", None, None)) # outer class scopes aren't used with self.scope.add_scope(ScopeType.class_scope, scope_node=None): self.scope.set("cls1", KnownValue(1), None, None) assert_eq(KnownValue(1), self.scope.get("cls1", None, None)) with self.scope.add_scope(ScopeType.class_scope, scope_node=None): self.scope.set("cls2", KnownValue(1), None, None) assert_eq(KnownValue(1), self.scope.get("cls2", None, None)) assert_is(UNINITIALIZED_VALUE, self.scope.get("cls1", None, None)) assert_eq(KnownValue(1), self.scope.get("cls1", None, None))
def test_message(): try: assert_is(1, None, message="custom message") except AssertionError as e: assert_in("custom message", str(e)) else: assert False, "should have thrown assertion error"
def test_format_error(): assert_is(None, asynq.debug.format_error(None)) # Syntax highlighting adds color text between words asynq.debug.enable_traceback_syntax_highlight(False) e = RuntimeError() expected = 'RuntimeError\n' assert_eq(expected, asynq.debug.format_error(e)) e._task = async_fn.asynq() formatted = asynq.debug.format_error(e) assert_in(expected, formatted) try: raise RuntimeError except RuntimeError: e._traceback = sys.exc_info()[2] formatted = asynq.debug.format_error(e) assert_in(expected, formatted) assert_in('Traceback', formatted) # Each single word, and unformatted text should be present asynq.debug.enable_traceback_syntax_highlight(True) expected = 'RuntimeError' formatted = asynq.debug.format_error(e) assert_in(expected, formatted) assert_in('Traceback', formatted)
def test_cached_hash_wrapper(): class TestClass(object): pass w1a = qcore.CachedHashWrapper(TestClass()) w1b = qcore.CachedHashWrapper(w1a()) w2a = qcore.CachedHashWrapper(TestClass()) print("w1a", w1a) print("w1b", w1b) print("w2a", w2a) assert_is(w1a.value(), w1a()) assert_is(w1a(), w1b()) assert_is_not(w1a(), w2a()) assert_eq(w1a, w1b) assert_ne(w1a, w2a) assert_ne(w1b, w2a) assert_eq(w1a, w1b()) assert_ne(w1a, w2a()) assert_ne(w1b, w2a()) assert_eq(hash(w1a), hash(w1b)) assert_ne(hash(w1a), hash(w2a)) assert_ne(hash(w1b), hash(w2a))
def test_message(): try: assert_is(1, None, message='custom message') except AssertionError as e: assert_in('custom message', str(e)) else: assert False, 'should have thrown assertion error'
def test_unbound_method_value() -> None: val = value.UnboundMethodValue("get_prop_with_get", value.TypedValue(tests.PropertyObject)) assert_eq("<method get_prop_with_get on pyanalyze.tests.PropertyObject>", str(val)) assert_eq("get_prop_with_get", val.attr_name) assert_eq(TypedValue(tests.PropertyObject), val.typ) assert_is(None, val.secondary_attr_name) assert_eq(tests.PropertyObject.get_prop_with_get, val.get_method()) assert val.is_type(object) assert not val.is_type(str) val = value.UnboundMethodValue( "get_prop_with_get", value.TypedValue(tests.PropertyObject), secondary_attr_name="asynq", ) assert_eq( "<method get_prop_with_get.asynq on pyanalyze.tests.PropertyObject>", str(val)) assert_eq("get_prop_with_get", val.attr_name) assert_eq(TypedValue(tests.PropertyObject), val.typ) assert_eq("asynq", val.secondary_attr_name) method = val.get_method() assert_is_not(None, method) assert_in(method.__name__, tests.ASYNQ_METHOD_NAMES) assert_eq(tests.PropertyObject.get_prop_with_get, method.__self__) assert val.is_type(object) assert not val.is_type(str)
def test_concrete_values_from_iterable() -> None: assert_is(None, concrete_values_from_iterable(KnownValue(1), CTX)) assert_eq((), concrete_values_from_iterable(KnownValue(()), CTX)) assert_eq( (KnownValue(1), KnownValue(2)), concrete_values_from_iterable(KnownValue((1, 2)), CTX), ) assert_eq( MultiValuedValue((KnownValue(1), KnownValue(2))), concrete_values_from_iterable( SequenceIncompleteValue( list, [KnownValue(1), KnownValue(2)]), CTX), ) assert_eq( TypedValue(int), concrete_values_from_iterable(GenericValue(list, [TypedValue(int)]), CTX), ) assert_eq( MultiValuedValue( [KnownValue(1), KnownValue(3), KnownValue(2), KnownValue(4)]), concrete_values_from_iterable( MultiValuedValue([ SequenceIncompleteValue( list, [KnownValue(1), KnownValue(2)]), KnownValue((3, 4)), ]), CTX, ), ) assert_eq( MultiValuedValue([KnownValue(1), KnownValue(2), TypedValue(int)]), concrete_values_from_iterable( MultiValuedValue([ SequenceIncompleteValue( list, [KnownValue(1), KnownValue(2)]), GenericValue(list, [TypedValue(int)]), ]), CTX, ), ) assert_eq( MultiValuedValue([KnownValue(1), KnownValue(2), KnownValue(3)]), concrete_values_from_iterable( MultiValuedValue([ SequenceIncompleteValue( list, [KnownValue(1), KnownValue(2)]), KnownValue((3, )), ]), CTX, ), )
def test_acached_per_instance_exception_handling(): obj = AsyncObject() try: obj.raises_exception() except AssertionError: # the exception should not affect the internals of the scheduler, and the active task # should get cleaned up assert_is(None, scheduler.get_active_task())
def _check_disabled(fn): try: from nose.plugins.skip import SkipTest except ImportError: assert_is(None, fn()) else: with AssertRaises(SkipTest): fn()
def test_decorate_func_or_method_or_class(): cls = _get_decoratable_class() new_cls = decorate_func_or_method_or_class(decorator)(cls) _assert_is_decorated(new_cls, cls) assert_is(marker, decorate_func_or_method_or_class(decorator)(normal_method)) with AssertRaises(AssertionError): decorate_func_or_method_or_class(decorator)(None)
def test_convert_result(): @convert_result(list) def test1(*args): for a in args: yield a result = test1(1, 2) assert_is(list, result.__class__) assert_eq([1, 2], result)
def test_get_async_fn(): assert_eq(async_fn.asynq, get_async_fn(async_fn)) assert_eq(lazy_fn, get_async_fn(lazy_fn)) assert_is(None, get_async_fn(sync_fn)) wrapper = get_async_fn(sync_fn, wrap_if_none=True) assert is_pure_async_fn(wrapper) result = wrapper() assert_is_instance(result, ConstFuture) assert_eq("sync_fn", result.value())
def outer_async(): """Test that we get the correct active task from the scheduler. Even when the execution of one task gets interrupted by a synchonous call to another async function, the scheduler retains the correct active task. """ active_task = scheduler.get_active_task() inner_async() assert_is(active_task, scheduler.get_active_task())
def capybara(cond): if cond: x = True else: x = False assert_is_value( x, MultiValuedValue([KnownValue(True), KnownValue(False)])) assert_is(x, True) assert_is_value(x, KnownValue(True))
def test_format_tb(mock_extract_tb, mock_format_list): mock_extract_tb.return_value = a_return_value mock_format_list.side_effect = lambda arg: arg traceback_to_verify = None try: async_function_whose_child_async_task_will_throw_an_error() except ValueError: traceback_to_verify = sys.exc_info()[2] assert_is(a_return_value, asynq.debug.format_tb(traceback_to_verify)) mock_extract_tb.assert_called_once_with(traceback_to_verify) mock_format_list.assert_called_once_with(a_return_value)
def test_debug_counter(): counter = qcore.debug.counter('test_debug_counter') counter_again = qcore.debug.counter('test_debug_counter') assert_is(counter, counter_again) counter.increment(5) assert_eq('DebugCounter(\'test_debug_counter\', value=5)', str(counter)) assert_eq('DebugCounter(\'test_debug_counter\', value=5)', repr(counter)) counter.decrement(3) assert_eq('DebugCounter(\'test_debug_counter\', value=2)', str(counter)) assert_eq('DebugCounter(\'test_debug_counter\', value=2)', repr(counter))
def test_debug_counter(): counter = qcore.debug.counter("test_debug_counter") counter_again = qcore.debug.counter("test_debug_counter") assert_is(counter, counter_again) counter.increment(5) assert_eq("DebugCounter('test_debug_counter', value=5)", str(counter)) assert_eq("DebugCounter('test_debug_counter', value=5)", repr(counter)) counter.decrement(3) assert_eq("DebugCounter('test_debug_counter', value=2)", str(counter)) assert_eq("DebugCounter('test_debug_counter', value=2)", repr(counter))
def test_gender(): assert_eq([2, 1], Gender._flag_values) assert_eq([Gender.undefined, Gender.male, Gender.female], Gender.get_members()) assert_eq(["undefined", "male", "female"], Gender.get_names()) assert_eq(3, len(Gender)) _assert_equality_both_directions(0, Gender.undefined, 1) _assert_equality_both_directions(1, Gender.male, 2) _assert_equality_both_directions(2, Gender.female, 3) _assert_equality_both_directions(Gender.undefined, Gender.parse("undefined"), Gender.male) _assert_equality_both_directions(Gender.male, Gender.parse("male"), Gender.female) _assert_equality_both_directions(Gender.female, Gender.parse("female"), Gender.male) _assert_equality_both_directions(Gender.undefined, Gender.parse(Gender.undefined), Gender.male) _assert_equality_both_directions(Gender.male, Gender.parse(Gender.male), Gender.female) _assert_equality_both_directions(Gender.female, Gender.parse(Gender.female), Gender.male) assert_is(None, Gender.parse("na", None)) assert_raises(lambda: Gender.parse("na"), KeyError) assert_raises(lambda: Gender.parse(SeparateEnum.undefined), KeyError) assert_raises(lambda: Gender.parse(b"ni\xc3\xb1o"), KeyError) assert_raises(lambda: Gender.parse("ni\xf1o"), KeyError) assert_raises(lambda: Gender.parse(b"ni\xff\xffo"), KeyError) assert_raises(lambda: Gender.parse("\xe4\xb8\xad\xe6\x96\x87"), KeyError) assert_eq("undefined", Gender(0).short_name) assert_eq("male", Gender(1).short_name) assert_eq("female", Gender(2).short_name) assert_eq("Gender.female", Gender.female.long_name) assert_eq("Female", Gender.female.title) assert_eq("test_enum.Gender.female", Gender.female.full_name) assert_is(None, Gender.parse("", None)) assert_is(None, Gender.parse(4, None)) assert_raises(lambda: Gender.parse(""), KeyError) assert_raises(lambda: Gender.parse(4), KeyError) assert_is(None, Gender("", None)) assert_is(None, Gender(4, None)) assert_raises(lambda: Gender(""), KeyError) assert_raises(lambda: Gender(4), KeyError) assert_eq(str(Gender.male), "male") assert_eq(repr(Gender.male), "Gender.male")
def test_values(): gen = generator_with_more_yields() for i in range(3): task = next(gen) assert_is_instance(task, AsyncTask) assert_eq(i, task.value()) task = next(gen) assert_is_instance(task, AsyncTask) assert_is(END_OF_GENERATOR, task.value()) with AssertRaises(StopIteration): next(gen)
def test_gender(): assert_eq([2, 1], Gender._flag_values) assert_eq([Gender.undefined, Gender.male, Gender.female], Gender.get_members()) assert_eq(['undefined', 'male', 'female'], Gender.get_names()) assert_eq(3, len(Gender)) _assert_equality_both_directions(0, Gender.undefined, 1) _assert_equality_both_directions(1, Gender.male, 2) _assert_equality_both_directions(2, Gender.female, 3) _assert_equality_both_directions( Gender.undefined, Gender.parse('undefined'), Gender.male) _assert_equality_both_directions( Gender.male, Gender.parse('male'), Gender.female) _assert_equality_both_directions( Gender.female, Gender.parse('female'), Gender.male) _assert_equality_both_directions( Gender.undefined, Gender.parse(Gender.undefined), Gender.male) _assert_equality_both_directions( Gender.male, Gender.parse(Gender.male), Gender.female) _assert_equality_both_directions( Gender.female, Gender.parse(Gender.female), Gender.male) assert_is(None, Gender.parse('na', None)) assert_raises(lambda: Gender.parse('na'), KeyError) assert_raises(lambda: Gender.parse(SeparateEnum.undefined), KeyError) assert_raises(lambda: Gender.parse(b'ni\xc3\xb1o'), KeyError) assert_raises(lambda: Gender.parse(u'ni\xf1o'), KeyError) assert_raises(lambda: Gender.parse(b'ni\xff\xffo'), KeyError) assert_raises(lambda: Gender.parse(u'\xe4\xb8\xad\xe6\x96\x87'), KeyError) assert_eq('undefined', Gender(0).short_name) assert_eq('male', Gender(1).short_name) assert_eq('female', Gender(2).short_name) assert_eq('Gender.female', Gender.female.long_name) assert_eq('Female', Gender.female.title) assert_eq('test_enum.Gender.female', Gender.female.full_name) assert_is(None, Gender.parse('', None)) assert_is(None, Gender.parse(4, None)) assert_raises(lambda: Gender.parse(''), KeyError) assert_raises(lambda: Gender.parse(4), KeyError) assert_is(None, Gender('', None)) assert_is(None, Gender(4, None)) assert_raises(lambda: Gender(''), KeyError) assert_raises(lambda: Gender(4), KeyError) assert_eq(str(Gender.male), 'male') assert_eq(repr(Gender.male), 'Gender.male')
def test_event_hub(): h = qcore.EventHub() assert_eq(0, len(h)) assert_eq('EventHub({})', repr(h)) with AssertRaises(AttributeError): h.doesnt_start_with_on h_e = h.on_e assert_is_instance(h_e, qcore.EventHook) assert_eq(1, len(h)) assert_is(h_e, h['e']) assert_eq("EventHub({'e': %r})" % h_e, repr(h)) assert_is(h, h.safe_trigger('e')) assert_is(h, h.trigger('e')) h_e.subscribe(lambda: 0) assert_in('e', h) assert_not_in('f', h) h['f'] = None assert_is(None, h['f']) assert_in('f', h) assert_eq(2, len(h)) del h['f'] assert_not_in('f', h) assert_eq(1, len(h)) for k, v in h: assert_eq('e', k) assert_is(h_e, v) def bad_fn(*args): raise NotImplementedError() m = mock.MagicMock() h.on_test.subscribe(bad_fn) with AssertRaises(NotImplementedError): h.on('test', m).safe_trigger('test', 1) m.assert_called_once_with(1) m.reset_mock() h.off('test', bad_fn).trigger('test', 2, 3) m.assert_called_once_with(2, 3)
def test_assert_is(): # Assign to val to make the assertion look more prototypical. val = None assert_is(None, val) assert_is(int, type(1)) with AssertRaises(AssertionError): assert_is(None, 1) with AssertRaises(AssertionError): assert_is(int, type("s"))
def test_format_error(): assert_is(None, asynq.debug.format_error(None)) e = RuntimeError() expected = '\nRuntimeError\n' assert_eq(expected, asynq.debug.format_error(e)) e._task = async_fn.asynq() formatted = asynq.debug.format_error(e) assert_in(expected, formatted) try: raise RuntimeError except RuntimeError: e._traceback = sys.exc_info()[2] formatted = asynq.debug.format_error(e) assert_in(expected, formatted) assert_in('Traceback', formatted)
def test_xyz(): assert_eq([8, 5, 4, 1], Xyz._flag_values) assert_eq([Xy.x, Xy.y, Xy.xy], Xy.get_members()) assert_eq([Xyz.x, Xyz.y, Xyz.xy, Xyz.z], Xyz.get_members()) assert_eq([Xyzna.na, Xyzna.x, Xyzna.y, Xyzna.xy, Xyzna.z], Xyzna.get_members()) assert_eq('[Xyzna.na, Xyzna.x, Xyzna.y, Xyzna.xy, Xyzna.z]', str(Xyzna.get_members())) assert_eq(0, Xyz.parse('')) assert_eq(0, Xyz.parse(0)) assert_eq(0, Xyzna.parse('na')) assert_is(None, Xyz.parse('na', None)) assert_eq(0, Xyz('')) assert_eq(0, Xyz(0)) assert_eq(0, Xyzna('na')) assert_is(None, Xyz('na', None)) assert_raises(lambda: Xyz.parse('_'), KeyError) assert_raises(lambda: Xyz.parse('x,_'), KeyError) assert_raises(lambda: Xyz('_'), KeyError) assert_raises(lambda: Xyz('x,_'), KeyError) assert_eq(4, Xyz.parse('y')) assert_eq(4, Xyz.parse(4)) assert_eq(4, Xyz('y')) assert_eq(4, Xyz(4)) assert_eq(5, Xyz.parse('xy')) assert_eq(5, Xyz.parse('x,y')) assert_eq(5, Xyz('xy')) assert_eq(5, Xyz('x,y')) assert_is(None, Xyz.parse(100, None)) assert_raises(lambda: Xyz.parse(100), KeyError) assert_is(None, Xyz(100, None)) assert_raises(lambda: Xyz(100), KeyError) assert_eq('x', Xyz(1).short_name) assert_eq('y', Xyz(4).short_name) assert_eq('xy', Xyz(5).short_name) assert_eq('z,xy', Xyz(8 | 5).short_name) assert_eq('', Xyz(0).short_name) assert_eq('na', Xyzna(0).short_name) assert_eq('z', str(Xyz.z)) assert_eq('Xyz.z', repr(Xyz.z)) assert_eq('xy', str(Xyz.xy)) assert_eq('Xyz.xy', repr(Xyz.xy)) assert_eq('z,x', str(Xyz.x | Xyz.z)) assert_eq("Xyz.parse('z,x')", repr(Xyz.x | Xyz.z))
def test_xyz(): assert_eq([8, 5, 4, 1], Xyz._flag_values) assert_eq([Xy.x, Xy.y, Xy.xy], Xy.get_members()) assert_eq([Xyz.x, Xyz.y, Xyz.xy, Xyz.z], Xyz.get_members()) assert_eq([Xyzna.na, Xyzna.x, Xyzna.y, Xyzna.xy, Xyzna.z], Xyzna.get_members()) assert_eq("[Xyzna.na, Xyzna.x, Xyzna.y, Xyzna.xy, Xyzna.z]", str(Xyzna.get_members())) assert_eq(0, Xyz.parse("")) assert_eq(0, Xyz.parse(0)) assert_eq(0, Xyzna.parse("na")) assert_is(None, Xyz.parse("na", None)) assert_eq(0, Xyz("")) assert_eq(0, Xyz(0)) assert_eq(0, Xyzna("na")) assert_is(None, Xyz("na", None)) assert_raises(lambda: Xyz.parse("_"), KeyError) assert_raises(lambda: Xyz.parse("x,_"), KeyError) assert_raises(lambda: Xyz("_"), KeyError) assert_raises(lambda: Xyz("x,_"), KeyError) assert_eq(4, Xyz.parse("y")) assert_eq(4, Xyz.parse(4)) assert_eq(4, Xyz("y")) assert_eq(4, Xyz(4)) assert_eq(5, Xyz.parse("xy")) assert_eq(5, Xyz.parse("x,y")) assert_eq(5, Xyz("xy")) assert_eq(5, Xyz("x,y")) assert_is(None, Xyz.parse(100, None)) assert_raises(lambda: Xyz.parse(100), KeyError) assert_is(None, Xyz(100, None)) assert_raises(lambda: Xyz(100), KeyError) assert_eq("x", Xyz(1).short_name) assert_eq("y", Xyz(4).short_name) assert_eq("xy", Xyz(5).short_name) assert_eq("z,xy", Xyz(8 | 5).short_name) assert_eq("", Xyz(0).short_name) assert_eq("na", Xyzna(0).short_name) assert_eq("z", str(Xyz.z)) assert_eq("Xyz.z", repr(Xyz.z)) assert_eq("xy", str(Xyz.xy)) assert_eq("Xyz.xy", repr(Xyz.xy)) assert_eq("z,x", str(Xyz.x | Xyz.z)) assert_eq("Xyz.parse('z,x')", repr(Xyz.x | Xyz.z))