test_methods_and_attributes.py revision 12037
111986Sandreas.sandberg@arm.comimport pytest 211986Sandreas.sandberg@arm.comfrom pybind11_tests import ExampleMandA, ConstructorStats 311986Sandreas.sandberg@arm.com 411986Sandreas.sandberg@arm.com 511986Sandreas.sandberg@arm.comdef test_methods_and_attributes(): 611986Sandreas.sandberg@arm.com instance1 = ExampleMandA() 711986Sandreas.sandberg@arm.com instance2 = ExampleMandA(32) 811986Sandreas.sandberg@arm.com 911986Sandreas.sandberg@arm.com instance1.add1(instance2) 1011986Sandreas.sandberg@arm.com instance1.add2(instance2) 1111986Sandreas.sandberg@arm.com instance1.add3(instance2) 1211986Sandreas.sandberg@arm.com instance1.add4(instance2) 1311986Sandreas.sandberg@arm.com instance1.add5(instance2) 1411986Sandreas.sandberg@arm.com instance1.add6(32) 1511986Sandreas.sandberg@arm.com instance1.add7(32) 1611986Sandreas.sandberg@arm.com instance1.add8(32) 1711986Sandreas.sandberg@arm.com instance1.add9(32) 1811986Sandreas.sandberg@arm.com instance1.add10(32) 1911986Sandreas.sandberg@arm.com 2011986Sandreas.sandberg@arm.com assert str(instance1) == "ExampleMandA[value=320]" 2111986Sandreas.sandberg@arm.com assert str(instance2) == "ExampleMandA[value=32]" 2211986Sandreas.sandberg@arm.com assert str(instance1.self1()) == "ExampleMandA[value=320]" 2311986Sandreas.sandberg@arm.com assert str(instance1.self2()) == "ExampleMandA[value=320]" 2411986Sandreas.sandberg@arm.com assert str(instance1.self3()) == "ExampleMandA[value=320]" 2511986Sandreas.sandberg@arm.com assert str(instance1.self4()) == "ExampleMandA[value=320]" 2611986Sandreas.sandberg@arm.com assert str(instance1.self5()) == "ExampleMandA[value=320]" 2711986Sandreas.sandberg@arm.com 2811986Sandreas.sandberg@arm.com assert instance1.internal1() == 320 2911986Sandreas.sandberg@arm.com assert instance1.internal2() == 320 3011986Sandreas.sandberg@arm.com assert instance1.internal3() == 320 3111986Sandreas.sandberg@arm.com assert instance1.internal4() == 320 3211986Sandreas.sandberg@arm.com assert instance1.internal5() == 320 3311986Sandreas.sandberg@arm.com 3411986Sandreas.sandberg@arm.com assert instance1.overloaded(1, 1.0) == "(int, float)" 3511986Sandreas.sandberg@arm.com assert instance1.overloaded(2.0, 2) == "(float, int)" 3612037Sandreas.sandberg@arm.com assert instance1.overloaded(3, 3) == "(int, int)" 3712037Sandreas.sandberg@arm.com assert instance1.overloaded(4., 4.) == "(float, float)" 3812037Sandreas.sandberg@arm.com assert instance1.overloaded_const(5, 5.0) == "(int, float) const" 3912037Sandreas.sandberg@arm.com assert instance1.overloaded_const(6.0, 6) == "(float, int) const" 4012037Sandreas.sandberg@arm.com assert instance1.overloaded_const(7, 7) == "(int, int) const" 4112037Sandreas.sandberg@arm.com assert instance1.overloaded_const(8., 8.) == "(float, float) const" 4212037Sandreas.sandberg@arm.com assert instance1.overloaded_float(1, 1) == "(float, float)" 4312037Sandreas.sandberg@arm.com assert instance1.overloaded_float(1, 1.) == "(float, float)" 4412037Sandreas.sandberg@arm.com assert instance1.overloaded_float(1., 1) == "(float, float)" 4512037Sandreas.sandberg@arm.com assert instance1.overloaded_float(1., 1.) == "(float, float)" 4611986Sandreas.sandberg@arm.com 4711986Sandreas.sandberg@arm.com assert instance1.value == 320 4811986Sandreas.sandberg@arm.com instance1.value = 100 4911986Sandreas.sandberg@arm.com assert str(instance1) == "ExampleMandA[value=100]" 5011986Sandreas.sandberg@arm.com 5111986Sandreas.sandberg@arm.com cstats = ConstructorStats.get(ExampleMandA) 5211986Sandreas.sandberg@arm.com assert cstats.alive() == 2 5311986Sandreas.sandberg@arm.com del instance1, instance2 5411986Sandreas.sandberg@arm.com assert cstats.alive() == 0 5511986Sandreas.sandberg@arm.com assert cstats.values() == ["32"] 5611986Sandreas.sandberg@arm.com assert cstats.default_constructions == 1 5711986Sandreas.sandberg@arm.com assert cstats.copy_constructions == 3 5811986Sandreas.sandberg@arm.com assert cstats.move_constructions >= 1 5911986Sandreas.sandberg@arm.com assert cstats.copy_assignments == 0 6011986Sandreas.sandberg@arm.com assert cstats.move_assignments == 0 6111986Sandreas.sandberg@arm.com 6211986Sandreas.sandberg@arm.com 6311986Sandreas.sandberg@arm.comdef test_properties(): 6411986Sandreas.sandberg@arm.com from pybind11_tests import TestProperties 6511986Sandreas.sandberg@arm.com 6611986Sandreas.sandberg@arm.com instance = TestProperties() 6711986Sandreas.sandberg@arm.com 6811986Sandreas.sandberg@arm.com assert instance.def_readonly == 1 6911986Sandreas.sandberg@arm.com with pytest.raises(AttributeError): 7011986Sandreas.sandberg@arm.com instance.def_readonly = 2 7111986Sandreas.sandberg@arm.com 7211986Sandreas.sandberg@arm.com instance.def_readwrite = 2 7311986Sandreas.sandberg@arm.com assert instance.def_readwrite == 2 7411986Sandreas.sandberg@arm.com 7511986Sandreas.sandberg@arm.com assert instance.def_property_readonly == 2 7611986Sandreas.sandberg@arm.com with pytest.raises(AttributeError): 7711986Sandreas.sandberg@arm.com instance.def_property_readonly = 3 7811986Sandreas.sandberg@arm.com 7911986Sandreas.sandberg@arm.com instance.def_property = 3 8011986Sandreas.sandberg@arm.com assert instance.def_property == 3 8111986Sandreas.sandberg@arm.com 8211986Sandreas.sandberg@arm.com 8311986Sandreas.sandberg@arm.comdef test_static_properties(): 8411986Sandreas.sandberg@arm.com from pybind11_tests import TestProperties as Type 8511986Sandreas.sandberg@arm.com 8611986Sandreas.sandberg@arm.com assert Type.def_readonly_static == 1 8712037Sandreas.sandberg@arm.com with pytest.raises(AttributeError) as excinfo: 8811986Sandreas.sandberg@arm.com Type.def_readonly_static = 2 8912037Sandreas.sandberg@arm.com assert "can't set attribute" in str(excinfo) 9011986Sandreas.sandberg@arm.com 9111986Sandreas.sandberg@arm.com Type.def_readwrite_static = 2 9211986Sandreas.sandberg@arm.com assert Type.def_readwrite_static == 2 9311986Sandreas.sandberg@arm.com 9411986Sandreas.sandberg@arm.com assert Type.def_property_readonly_static == 2 9512037Sandreas.sandberg@arm.com with pytest.raises(AttributeError) as excinfo: 9611986Sandreas.sandberg@arm.com Type.def_property_readonly_static = 3 9712037Sandreas.sandberg@arm.com assert "can't set attribute" in str(excinfo) 9811986Sandreas.sandberg@arm.com 9911986Sandreas.sandberg@arm.com Type.def_property_static = 3 10011986Sandreas.sandberg@arm.com assert Type.def_property_static == 3 10111986Sandreas.sandberg@arm.com 10212037Sandreas.sandberg@arm.com # Static property read and write via instance 10312037Sandreas.sandberg@arm.com instance = Type() 10412037Sandreas.sandberg@arm.com 10512037Sandreas.sandberg@arm.com Type.def_readwrite_static = 0 10612037Sandreas.sandberg@arm.com assert Type.def_readwrite_static == 0 10712037Sandreas.sandberg@arm.com assert instance.def_readwrite_static == 0 10812037Sandreas.sandberg@arm.com 10912037Sandreas.sandberg@arm.com instance.def_readwrite_static = 2 11012037Sandreas.sandberg@arm.com assert Type.def_readwrite_static == 2 11112037Sandreas.sandberg@arm.com assert instance.def_readwrite_static == 2 11212037Sandreas.sandberg@arm.com 11312037Sandreas.sandberg@arm.com 11412037Sandreas.sandberg@arm.comdef test_static_cls(): 11512037Sandreas.sandberg@arm.com """Static property getter and setters expect the type object as the their only argument""" 11612037Sandreas.sandberg@arm.com from pybind11_tests import TestProperties as Type 11712037Sandreas.sandberg@arm.com 11812037Sandreas.sandberg@arm.com instance = Type() 11912037Sandreas.sandberg@arm.com assert Type.static_cls is Type 12012037Sandreas.sandberg@arm.com assert instance.static_cls is Type 12112037Sandreas.sandberg@arm.com 12212037Sandreas.sandberg@arm.com def check_self(self): 12312037Sandreas.sandberg@arm.com assert self is Type 12412037Sandreas.sandberg@arm.com 12512037Sandreas.sandberg@arm.com Type.static_cls = check_self 12612037Sandreas.sandberg@arm.com instance.static_cls = check_self 12712037Sandreas.sandberg@arm.com 12812037Sandreas.sandberg@arm.com 12912037Sandreas.sandberg@arm.comdef test_metaclass_override(): 13012037Sandreas.sandberg@arm.com """Overriding pybind11's default metaclass changes the behavior of `static_property`""" 13112037Sandreas.sandberg@arm.com from pybind11_tests import MetaclassOverride 13212037Sandreas.sandberg@arm.com 13312037Sandreas.sandberg@arm.com assert type(ExampleMandA).__name__ == "pybind11_type" 13412037Sandreas.sandberg@arm.com assert type(MetaclassOverride).__name__ == "type" 13512037Sandreas.sandberg@arm.com 13612037Sandreas.sandberg@arm.com assert MetaclassOverride.readonly == 1 13712037Sandreas.sandberg@arm.com assert type(MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property" 13812037Sandreas.sandberg@arm.com 13912037Sandreas.sandberg@arm.com # Regular `type` replaces the property instead of calling `__set__()` 14012037Sandreas.sandberg@arm.com MetaclassOverride.readonly = 2 14112037Sandreas.sandberg@arm.com assert MetaclassOverride.readonly == 2 14212037Sandreas.sandberg@arm.com assert isinstance(MetaclassOverride.__dict__["readonly"], int) 14312037Sandreas.sandberg@arm.com 14411986Sandreas.sandberg@arm.com 14511986Sandreas.sandberg@arm.com@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) 14611986Sandreas.sandberg@arm.comdef test_property_return_value_policies(access): 14711986Sandreas.sandberg@arm.com from pybind11_tests import TestPropRVP 14811986Sandreas.sandberg@arm.com 14911986Sandreas.sandberg@arm.com if not access.startswith("static"): 15011986Sandreas.sandberg@arm.com obj = TestPropRVP() 15111986Sandreas.sandberg@arm.com else: 15211986Sandreas.sandberg@arm.com obj = TestPropRVP 15311986Sandreas.sandberg@arm.com 15411986Sandreas.sandberg@arm.com ref = getattr(obj, access + "_ref") 15511986Sandreas.sandberg@arm.com assert ref.value == 1 15611986Sandreas.sandberg@arm.com ref.value = 2 15711986Sandreas.sandberg@arm.com assert getattr(obj, access + "_ref").value == 2 15811986Sandreas.sandberg@arm.com ref.value = 1 # restore original value for static properties 15911986Sandreas.sandberg@arm.com 16011986Sandreas.sandberg@arm.com copy = getattr(obj, access + "_copy") 16111986Sandreas.sandberg@arm.com assert copy.value == 1 16211986Sandreas.sandberg@arm.com copy.value = 2 16311986Sandreas.sandberg@arm.com assert getattr(obj, access + "_copy").value == 1 16411986Sandreas.sandberg@arm.com 16511986Sandreas.sandberg@arm.com copy = getattr(obj, access + "_func") 16611986Sandreas.sandberg@arm.com assert copy.value == 1 16711986Sandreas.sandberg@arm.com copy.value = 2 16811986Sandreas.sandberg@arm.com assert getattr(obj, access + "_func").value == 1 16911986Sandreas.sandberg@arm.com 17011986Sandreas.sandberg@arm.com 17111986Sandreas.sandberg@arm.comdef test_property_rvalue_policy(): 17211986Sandreas.sandberg@arm.com """When returning an rvalue, the return value policy is automatically changed from 17311986Sandreas.sandberg@arm.com `reference(_internal)` to `move`. The following would not work otherwise. 17411986Sandreas.sandberg@arm.com """ 17511986Sandreas.sandberg@arm.com from pybind11_tests import TestPropRVP 17611986Sandreas.sandberg@arm.com 17711986Sandreas.sandberg@arm.com instance = TestPropRVP() 17811986Sandreas.sandberg@arm.com o = instance.rvalue 17911986Sandreas.sandberg@arm.com assert o.value == 1 18012037Sandreas.sandberg@arm.com 18112037Sandreas.sandberg@arm.com 18212037Sandreas.sandberg@arm.comdef test_property_rvalue_policy_static(): 18312037Sandreas.sandberg@arm.com """When returning an rvalue, the return value policy is automatically changed from 18412037Sandreas.sandberg@arm.com `reference(_internal)` to `move`. The following would not work otherwise. 18512037Sandreas.sandberg@arm.com """ 18612037Sandreas.sandberg@arm.com from pybind11_tests import TestPropRVP 18711986Sandreas.sandberg@arm.com o = TestPropRVP.static_rvalue 18811986Sandreas.sandberg@arm.com assert o.value == 1 18911986Sandreas.sandberg@arm.com 19011986Sandreas.sandberg@arm.com 19112037Sandreas.sandberg@arm.com# https://bitbucket.org/pypy/pypy/issues/2447 19212037Sandreas.sandberg@arm.com@pytest.unsupported_on_pypy 19311986Sandreas.sandberg@arm.comdef test_dynamic_attributes(): 19411986Sandreas.sandberg@arm.com from pybind11_tests import DynamicClass, CppDerivedDynamicClass 19511986Sandreas.sandberg@arm.com 19611986Sandreas.sandberg@arm.com instance = DynamicClass() 19711986Sandreas.sandberg@arm.com assert not hasattr(instance, "foo") 19811986Sandreas.sandberg@arm.com assert "foo" not in dir(instance) 19911986Sandreas.sandberg@arm.com 20011986Sandreas.sandberg@arm.com # Dynamically add attribute 20111986Sandreas.sandberg@arm.com instance.foo = 42 20211986Sandreas.sandberg@arm.com assert hasattr(instance, "foo") 20311986Sandreas.sandberg@arm.com assert instance.foo == 42 20411986Sandreas.sandberg@arm.com assert "foo" in dir(instance) 20511986Sandreas.sandberg@arm.com 20611986Sandreas.sandberg@arm.com # __dict__ should be accessible and replaceable 20711986Sandreas.sandberg@arm.com assert "foo" in instance.__dict__ 20811986Sandreas.sandberg@arm.com instance.__dict__ = {"bar": True} 20911986Sandreas.sandberg@arm.com assert not hasattr(instance, "foo") 21011986Sandreas.sandberg@arm.com assert hasattr(instance, "bar") 21111986Sandreas.sandberg@arm.com 21211986Sandreas.sandberg@arm.com with pytest.raises(TypeError) as excinfo: 21311986Sandreas.sandberg@arm.com instance.__dict__ = [] 21411986Sandreas.sandberg@arm.com assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'" 21511986Sandreas.sandberg@arm.com 21611986Sandreas.sandberg@arm.com cstats = ConstructorStats.get(DynamicClass) 21711986Sandreas.sandberg@arm.com assert cstats.alive() == 1 21811986Sandreas.sandberg@arm.com del instance 21911986Sandreas.sandberg@arm.com assert cstats.alive() == 0 22011986Sandreas.sandberg@arm.com 22111986Sandreas.sandberg@arm.com # Derived classes should work as well 22211986Sandreas.sandberg@arm.com class PythonDerivedDynamicClass(DynamicClass): 22311986Sandreas.sandberg@arm.com pass 22411986Sandreas.sandberg@arm.com 22511986Sandreas.sandberg@arm.com for cls in CppDerivedDynamicClass, PythonDerivedDynamicClass: 22611986Sandreas.sandberg@arm.com derived = cls() 22711986Sandreas.sandberg@arm.com derived.foobar = 100 22811986Sandreas.sandberg@arm.com assert derived.foobar == 100 22911986Sandreas.sandberg@arm.com 23011986Sandreas.sandberg@arm.com assert cstats.alive() == 1 23111986Sandreas.sandberg@arm.com del derived 23211986Sandreas.sandberg@arm.com assert cstats.alive() == 0 23311986Sandreas.sandberg@arm.com 23411986Sandreas.sandberg@arm.com 23512037Sandreas.sandberg@arm.com# https://bitbucket.org/pypy/pypy/issues/2447 23612037Sandreas.sandberg@arm.com@pytest.unsupported_on_pypy 23711986Sandreas.sandberg@arm.comdef test_cyclic_gc(): 23811986Sandreas.sandberg@arm.com from pybind11_tests import DynamicClass 23911986Sandreas.sandberg@arm.com 24011986Sandreas.sandberg@arm.com # One object references itself 24111986Sandreas.sandberg@arm.com instance = DynamicClass() 24211986Sandreas.sandberg@arm.com instance.circular_reference = instance 24311986Sandreas.sandberg@arm.com 24411986Sandreas.sandberg@arm.com cstats = ConstructorStats.get(DynamicClass) 24511986Sandreas.sandberg@arm.com assert cstats.alive() == 1 24611986Sandreas.sandberg@arm.com del instance 24711986Sandreas.sandberg@arm.com assert cstats.alive() == 0 24811986Sandreas.sandberg@arm.com 24911986Sandreas.sandberg@arm.com # Two object reference each other 25011986Sandreas.sandberg@arm.com i1 = DynamicClass() 25111986Sandreas.sandberg@arm.com i2 = DynamicClass() 25211986Sandreas.sandberg@arm.com i1.cycle = i2 25311986Sandreas.sandberg@arm.com i2.cycle = i1 25411986Sandreas.sandberg@arm.com 25511986Sandreas.sandberg@arm.com assert cstats.alive() == 2 25611986Sandreas.sandberg@arm.com del i1, i2 25711986Sandreas.sandberg@arm.com assert cstats.alive() == 0 25812037Sandreas.sandberg@arm.com 25912037Sandreas.sandberg@arm.com 26012037Sandreas.sandberg@arm.comdef test_noconvert_args(msg): 26112037Sandreas.sandberg@arm.com from pybind11_tests import ArgInspector, arg_inspect_func, floats_only, floats_preferred 26212037Sandreas.sandberg@arm.com 26312037Sandreas.sandberg@arm.com a = ArgInspector() 26412037Sandreas.sandberg@arm.com assert msg(a.f("hi")) == """ 26512037Sandreas.sandberg@arm.com loading ArgInspector1 argument WITH conversion allowed. Argument value = hi 26612037Sandreas.sandberg@arm.com """ 26712037Sandreas.sandberg@arm.com assert msg(a.g("this is a", "this is b")) == """ 26812037Sandreas.sandberg@arm.com loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a 26912037Sandreas.sandberg@arm.com loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b 27012037Sandreas.sandberg@arm.com 13 27112037Sandreas.sandberg@arm.com loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) 27212037Sandreas.sandberg@arm.com """ # noqa: E501 line too long 27312037Sandreas.sandberg@arm.com assert msg(a.g("this is a", "this is b", 42)) == """ 27412037Sandreas.sandberg@arm.com loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a 27512037Sandreas.sandberg@arm.com loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b 27612037Sandreas.sandberg@arm.com 42 27712037Sandreas.sandberg@arm.com loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) 27812037Sandreas.sandberg@arm.com """ # noqa: E501 line too long 27912037Sandreas.sandberg@arm.com assert msg(a.g("this is a", "this is b", 42, "this is d")) == """ 28012037Sandreas.sandberg@arm.com loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a 28112037Sandreas.sandberg@arm.com loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b 28212037Sandreas.sandberg@arm.com 42 28312037Sandreas.sandberg@arm.com loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d 28412037Sandreas.sandberg@arm.com """ 28512037Sandreas.sandberg@arm.com assert (a.h("arg 1") == 28612037Sandreas.sandberg@arm.com "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1") 28712037Sandreas.sandberg@arm.com assert msg(arg_inspect_func("A1", "A2")) == """ 28812037Sandreas.sandberg@arm.com loading ArgInspector2 argument WITH conversion allowed. Argument value = A1 28912037Sandreas.sandberg@arm.com loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2 29012037Sandreas.sandberg@arm.com """ 29112037Sandreas.sandberg@arm.com 29212037Sandreas.sandberg@arm.com assert floats_preferred(4) == 2.0 29312037Sandreas.sandberg@arm.com assert floats_only(4.0) == 2.0 29412037Sandreas.sandberg@arm.com with pytest.raises(TypeError) as excinfo: 29512037Sandreas.sandberg@arm.com floats_only(4) 29612037Sandreas.sandberg@arm.com assert msg(excinfo.value) == """ 29712037Sandreas.sandberg@arm.com floats_only(): incompatible function arguments. The following argument types are supported: 29812037Sandreas.sandberg@arm.com 1. (f: float) -> float 29912037Sandreas.sandberg@arm.com 30012037Sandreas.sandberg@arm.com Invoked with: 4 30112037Sandreas.sandberg@arm.com """ 30212037Sandreas.sandberg@arm.com 30312037Sandreas.sandberg@arm.com 30412037Sandreas.sandberg@arm.comdef test_bad_arg_default(msg): 30512037Sandreas.sandberg@arm.com from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed 30612037Sandreas.sandberg@arm.com 30712037Sandreas.sandberg@arm.com with pytest.raises(RuntimeError) as excinfo: 30812037Sandreas.sandberg@arm.com bad_arg_def_named() 30912037Sandreas.sandberg@arm.com assert msg(excinfo.value) == ( 31012037Sandreas.sandberg@arm.com "arg(): could not convert default argument 'a: NotRegistered' in function 'should_fail' " 31112037Sandreas.sandberg@arm.com "into a Python object (type not registered yet?)" 31212037Sandreas.sandberg@arm.com if debug_enabled else 31312037Sandreas.sandberg@arm.com "arg(): could not convert default argument into a Python object (type not registered " 31412037Sandreas.sandberg@arm.com "yet?). Compile in debug mode for more information." 31512037Sandreas.sandberg@arm.com ) 31612037Sandreas.sandberg@arm.com 31712037Sandreas.sandberg@arm.com with pytest.raises(RuntimeError) as excinfo: 31812037Sandreas.sandberg@arm.com bad_arg_def_unnamed() 31912037Sandreas.sandberg@arm.com assert msg(excinfo.value) == ( 32012037Sandreas.sandberg@arm.com "arg(): could not convert default argument 'NotRegistered' in function 'should_fail' " 32112037Sandreas.sandberg@arm.com "into a Python object (type not registered yet?)" 32212037Sandreas.sandberg@arm.com if debug_enabled else 32312037Sandreas.sandberg@arm.com "arg(): could not convert default argument into a Python object (type not registered " 32412037Sandreas.sandberg@arm.com "yet?). Compile in debug mode for more information." 32512037Sandreas.sandberg@arm.com ) 326