Commit 2a757844 by Jason Rhinelander Committed by Wenzel Jakob

Move requires_numpy, etc. decorators to globals

test_eigen.py and test_numpy_*.py have the same
@pytest.requires_eigen_and_numpy or @pytest.requires_numpy on every
single test; this changes them to use pytest's global `pytestmark = ...`
instead to disable the entire module when numpy and/or eigen aren't
available.
parent 17d0283e
import pytest import pytest
pytestmark = pytest.requires_eigen_and_numpy
with pytest.suppress(ImportError): with pytest.suppress(ImportError):
import numpy as np import numpy as np
...@@ -18,7 +20,6 @@ def assert_sparse_equal_ref(sparse_mat): ...@@ -18,7 +20,6 @@ def assert_sparse_equal_ref(sparse_mat):
assert_equal_ref(sparse_mat.todense()) assert_equal_ref(sparse_mat.todense())
@pytest.requires_eigen_and_numpy
def test_fixed(): def test_fixed():
from pybind11_tests import fixed_r, fixed_c, fixed_copy_r, fixed_copy_c from pybind11_tests import fixed_r, fixed_c, fixed_copy_r, fixed_copy_c
...@@ -30,7 +31,6 @@ def test_fixed(): ...@@ -30,7 +31,6 @@ def test_fixed():
assert_equal_ref(fixed_copy_c(fixed_r())) assert_equal_ref(fixed_copy_c(fixed_r()))
@pytest.requires_eigen_and_numpy
def test_dense(): def test_dense():
from pybind11_tests import dense_r, dense_c, dense_copy_r, dense_copy_c from pybind11_tests import dense_r, dense_c, dense_copy_r, dense_copy_c
...@@ -42,7 +42,6 @@ def test_dense(): ...@@ -42,7 +42,6 @@ def test_dense():
assert_equal_ref(dense_copy_c(dense_r())) assert_equal_ref(dense_copy_c(dense_r()))
@pytest.requires_eigen_and_numpy
def test_partially_fixed(): def test_partially_fixed():
from pybind11_tests import (partial_copy_four_rm_r, partial_copy_four_rm_c, from pybind11_tests import (partial_copy_four_rm_r, partial_copy_four_rm_c,
partial_copy_four_cm_r, partial_copy_four_cm_c) partial_copy_four_cm_r, partial_copy_four_cm_c)
...@@ -65,7 +64,6 @@ def test_partially_fixed(): ...@@ -65,7 +64,6 @@ def test_partially_fixed():
partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]) partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :])
@pytest.requires_eigen_and_numpy
def test_mutator_descriptors(): def test_mutator_descriptors():
from pybind11_tests import fixed_mutator_r, fixed_mutator_c, fixed_mutator_a from pybind11_tests import fixed_mutator_r, fixed_mutator_c, fixed_mutator_a
zr = np.arange(30, dtype='float32').reshape(5, 6) # row-major zr = np.arange(30, dtype='float32').reshape(5, 6) # row-major
...@@ -94,7 +92,6 @@ def test_mutator_descriptors(): ...@@ -94,7 +92,6 @@ def test_mutator_descriptors():
fixed_mutator_a(zr) fixed_mutator_a(zr)
@pytest.requires_eigen_and_numpy
def test_cpp_casting(): def test_cpp_casting():
from pybind11_tests import (cpp_copy, cpp_ref_c, cpp_ref_r, cpp_ref_any, from pybind11_tests import (cpp_copy, cpp_ref_c, cpp_ref_r, cpp_ref_any,
fixed_r, fixed_c, get_cm_ref, get_rm_ref, ReturnTester) fixed_r, fixed_c, get_cm_ref, get_rm_ref, ReturnTester)
...@@ -120,7 +117,6 @@ def test_cpp_casting(): ...@@ -120,7 +117,6 @@ def test_cpp_casting():
assert cpp_ref_any(get_cm_ref()) == 21. assert cpp_ref_any(get_cm_ref()) == 21.
@pytest.requires_eigen_and_numpy
def test_pass_readonly_array(): def test_pass_readonly_array():
from pybind11_tests import fixed_copy_r, fixed_r, fixed_r_const from pybind11_tests import fixed_copy_r, fixed_r, fixed_r_const
z = np.full((5, 6), 42.0) z = np.full((5, 6), 42.0)
...@@ -131,7 +127,6 @@ def test_pass_readonly_array(): ...@@ -131,7 +127,6 @@ def test_pass_readonly_array():
np.testing.assert_array_equal(fixed_copy_r(fixed_r_const()), fixed_r_const()) np.testing.assert_array_equal(fixed_copy_r(fixed_r_const()), fixed_r_const())
@pytest.requires_eigen_and_numpy
def test_nonunit_stride_from_python(): def test_nonunit_stride_from_python():
from pybind11_tests import ( from pybind11_tests import (
double_row, double_col, double_mat_cm, double_mat_rm, double_row, double_col, double_mat_cm, double_mat_rm,
...@@ -157,7 +152,6 @@ def test_nonunit_stride_from_python(): ...@@ -157,7 +152,6 @@ def test_nonunit_stride_from_python():
np.testing.assert_array_equal(counting_mat, [[0., 2, 2], [6, 16, 10], [6, 14, 8]]) np.testing.assert_array_equal(counting_mat, [[0., 2, 2], [6, 16, 10], [6, 14, 8]])
@pytest.requires_eigen_and_numpy
def test_nonunit_stride_to_python(): def test_nonunit_stride_to_python():
from pybind11_tests import diagonal, diagonal_1, diagonal_n, block from pybind11_tests import diagonal, diagonal_1, diagonal_n, block
...@@ -171,7 +165,6 @@ def test_nonunit_stride_to_python(): ...@@ -171,7 +165,6 @@ def test_nonunit_stride_to_python():
assert np.all(block(ref, 1, 4, 3, 2) == ref[1:4, 4:]) assert np.all(block(ref, 1, 4, 3, 2) == ref[1:4, 4:])
@pytest.requires_eigen_and_numpy
def test_eigen_ref_to_python(): def test_eigen_ref_to_python():
from pybind11_tests import cholesky1, cholesky2, cholesky3, cholesky4 from pybind11_tests import cholesky1, cholesky2, cholesky3, cholesky4
...@@ -192,7 +185,6 @@ def array_copy_but_one(a, r, c, v): ...@@ -192,7 +185,6 @@ def array_copy_but_one(a, r, c, v):
return z return z
@pytest.requires_eigen_and_numpy
def test_eigen_return_references(): def test_eigen_return_references():
"""Tests various ways of returning references and non-referencing copies""" """Tests various ways of returning references and non-referencing copies"""
from pybind11_tests import ReturnTester from pybind11_tests import ReturnTester
...@@ -322,7 +314,6 @@ def assert_keeps_alive(cl, method, *args): ...@@ -322,7 +314,6 @@ def assert_keeps_alive(cl, method, *args):
assert cstats.alive() == start_with assert cstats.alive() == start_with
@pytest.requires_eigen_and_numpy
def test_eigen_keepalive(): def test_eigen_keepalive():
from pybind11_tests import ReturnTester, ConstructorStats from pybind11_tests import ReturnTester, ConstructorStats
a = ReturnTester() a = ReturnTester()
...@@ -346,7 +337,6 @@ def test_eigen_keepalive(): ...@@ -346,7 +337,6 @@ def test_eigen_keepalive():
assert_keeps_alive(ReturnTester, meth, 4, 3, 2, 1) assert_keeps_alive(ReturnTester, meth, 4, 3, 2, 1)
@pytest.requires_eigen_and_numpy
def test_eigen_ref_mutators(): def test_eigen_ref_mutators():
"""Tests whether Eigen can mutate numpy values""" """Tests whether Eigen can mutate numpy values"""
from pybind11_tests import add_rm, add_cm, add_any, add1, add2 from pybind11_tests import add_rm, add_cm, add_any, add1, add2
...@@ -416,7 +406,6 @@ def test_eigen_ref_mutators(): ...@@ -416,7 +406,6 @@ def test_eigen_ref_mutators():
add_rm(zi) add_rm(zi)
@pytest.requires_eigen_and_numpy
def test_numpy_ref_mutators(): def test_numpy_ref_mutators():
"""Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)""" """Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)"""
from pybind11_tests import ( from pybind11_tests import (
...@@ -465,7 +454,6 @@ def test_numpy_ref_mutators(): ...@@ -465,7 +454,6 @@ def test_numpy_ref_mutators():
assert zc[1, 2] == 99 # Make sure we aren't referencing the original assert zc[1, 2] == 99 # Make sure we aren't referencing the original
@pytest.requires_eigen_and_numpy
def test_both_ref_mutators(): def test_both_ref_mutators():
"""Tests a complex chain of nested eigen/numpy references""" """Tests a complex chain of nested eigen/numpy references"""
from pybind11_tests import ( from pybind11_tests import (
...@@ -509,7 +497,6 @@ def test_both_ref_mutators(): ...@@ -509,7 +497,6 @@ def test_both_ref_mutators():
assert np.all(y == yexpect) assert np.all(y == yexpect)
@pytest.requires_eigen_and_numpy
def test_nocopy_wrapper(): def test_nocopy_wrapper():
from pybind11_tests import get_elem, get_elem_nocopy, get_elem_rm_nocopy from pybind11_tests import get_elem, get_elem_nocopy, get_elem_rm_nocopy
# get_elem requires a column-contiguous matrix reference, but should be # get_elem requires a column-contiguous matrix reference, but should be
...@@ -556,7 +543,6 @@ def test_nocopy_wrapper(): ...@@ -556,7 +543,6 @@ def test_nocopy_wrapper():
', flags.c_contiguous' in str(excinfo.value)) ', flags.c_contiguous' in str(excinfo.value))
@pytest.requires_eigen_and_numpy
def test_special_matrix_objects(): def test_special_matrix_objects():
from pybind11_tests import incr_diag, symmetric_upper, symmetric_lower from pybind11_tests import incr_diag, symmetric_upper, symmetric_lower
...@@ -577,7 +563,6 @@ def test_special_matrix_objects(): ...@@ -577,7 +563,6 @@ def test_special_matrix_objects():
assert np.all(symmetric_upper(asymm) == symm_upper) assert np.all(symmetric_upper(asymm) == symm_upper)
@pytest.requires_eigen_and_numpy
def test_dense_signature(doc): def test_dense_signature(doc):
from pybind11_tests import double_col, double_row, double_mat_rm from pybind11_tests import double_col, double_row, double_mat_rm
......
import pytest import pytest
pytestmark = pytest.requires_numpy
with pytest.suppress(ImportError): with pytest.suppress(ImportError):
import numpy as np import numpy as np
...@@ -9,7 +11,6 @@ def arr(): ...@@ -9,7 +11,6 @@ def arr():
return np.array([[1, 2, 3], [4, 5, 6]], '<u2') return np.array([[1, 2, 3], [4, 5, 6]], '<u2')
@pytest.requires_numpy
def test_array_attributes(): def test_array_attributes():
from pybind11_tests.array import ( from pybind11_tests.array import (
ndim, shape, strides, writeable, size, itemsize, nbytes, owndata ndim, shape, strides, writeable, size, itemsize, nbytes, owndata
...@@ -53,7 +54,6 @@ def test_array_attributes(): ...@@ -53,7 +54,6 @@ def test_array_attributes():
assert not owndata(a) assert not owndata(a)
@pytest.requires_numpy
@pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)]) @pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)])
def test_index_offset(arr, args, ret): def test_index_offset(arr, args, ret):
from pybind11_tests.array import index_at, index_at_t, offset_at, offset_at_t from pybind11_tests.array import index_at, index_at_t, offset_at, offset_at_t
...@@ -63,7 +63,6 @@ def test_index_offset(arr, args, ret): ...@@ -63,7 +63,6 @@ def test_index_offset(arr, args, ret):
assert offset_at_t(arr, *args) == ret * arr.dtype.itemsize assert offset_at_t(arr, *args) == ret * arr.dtype.itemsize
@pytest.requires_numpy
def test_dim_check_fail(arr): def test_dim_check_fail(arr):
from pybind11_tests.array import (index_at, index_at_t, offset_at, offset_at_t, data, data_t, from pybind11_tests.array import (index_at, index_at_t, offset_at, offset_at_t, data, data_t,
mutate_data, mutate_data_t) mutate_data, mutate_data_t)
...@@ -74,7 +73,6 @@ def test_dim_check_fail(arr): ...@@ -74,7 +73,6 @@ def test_dim_check_fail(arr):
assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)' assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)'
@pytest.requires_numpy
@pytest.mark.parametrize('args, ret', @pytest.mark.parametrize('args, ret',
[([], [1, 2, 3, 4, 5, 6]), [([], [1, 2, 3, 4, 5, 6]),
([1], [4, 5, 6]), ([1], [4, 5, 6]),
...@@ -87,7 +85,6 @@ def test_data(arr, args, ret): ...@@ -87,7 +85,6 @@ def test_data(arr, args, ret):
assert all(data(arr, *args)[1::2] == 0) assert all(data(arr, *args)[1::2] == 0)
@pytest.requires_numpy
def test_mutate_readonly(arr): def test_mutate_readonly(arr):
from pybind11_tests.array import mutate_data, mutate_data_t, mutate_at_t from pybind11_tests.array import mutate_data, mutate_data_t, mutate_at_t
arr.flags.writeable = False arr.flags.writeable = False
...@@ -97,7 +94,6 @@ def test_mutate_readonly(arr): ...@@ -97,7 +94,6 @@ def test_mutate_readonly(arr):
assert str(excinfo.value) == 'array is not writeable' assert str(excinfo.value) == 'array is not writeable'
@pytest.requires_numpy
@pytest.mark.parametrize('dim', [0, 1, 3]) @pytest.mark.parametrize('dim', [0, 1, 3])
def test_at_fail(arr, dim): def test_at_fail(arr, dim):
from pybind11_tests.array import at_t, mutate_at_t from pybind11_tests.array import at_t, mutate_at_t
...@@ -107,7 +103,6 @@ def test_at_fail(arr, dim): ...@@ -107,7 +103,6 @@ def test_at_fail(arr, dim):
assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim) assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim)
@pytest.requires_numpy
def test_at(arr): def test_at(arr):
from pybind11_tests.array import at_t, mutate_at_t from pybind11_tests.array import at_t, mutate_at_t
...@@ -118,7 +113,6 @@ def test_at(arr): ...@@ -118,7 +113,6 @@ def test_at(arr):
assert all(mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6]) assert all(mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6])
@pytest.requires_numpy
def test_mutate_data(arr): def test_mutate_data(arr):
from pybind11_tests.array import mutate_data, mutate_data_t from pybind11_tests.array import mutate_data, mutate_data_t
...@@ -135,7 +129,6 @@ def test_mutate_data(arr): ...@@ -135,7 +129,6 @@ def test_mutate_data(arr):
assert all(mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197]) assert all(mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197])
@pytest.requires_numpy
def test_bounds_check(arr): def test_bounds_check(arr):
from pybind11_tests.array import (index_at, index_at_t, data, data_t, from pybind11_tests.array import (index_at, index_at_t, data, data_t,
mutate_data, mutate_data_t, at_t, mutate_at_t) mutate_data, mutate_data_t, at_t, mutate_at_t)
...@@ -150,7 +143,6 @@ def test_bounds_check(arr): ...@@ -150,7 +143,6 @@ def test_bounds_check(arr):
assert str(excinfo.value) == 'index 4 is out of bounds for axis 1 with size 3' assert str(excinfo.value) == 'index 4 is out of bounds for axis 1 with size 3'
@pytest.requires_numpy
def test_make_c_f_array(): def test_make_c_f_array():
from pybind11_tests.array import ( from pybind11_tests.array import (
make_c_array, make_f_array make_c_array, make_f_array
...@@ -161,7 +153,6 @@ def test_make_c_f_array(): ...@@ -161,7 +153,6 @@ def test_make_c_f_array():
assert not make_f_array().flags.c_contiguous assert not make_f_array().flags.c_contiguous
@pytest.requires_numpy
def test_wrap(): def test_wrap():
from pybind11_tests.array import wrap from pybind11_tests.array import wrap
...@@ -212,7 +203,6 @@ def test_wrap(): ...@@ -212,7 +203,6 @@ def test_wrap():
assert_references(a1d, a2, a1) assert_references(a1d, a2, a1)
@pytest.requires_numpy
def test_numpy_view(capture): def test_numpy_view(capture):
from pybind11_tests.array import ArrayClass from pybind11_tests.array import ArrayClass
with capture: with capture:
...@@ -242,14 +232,12 @@ def test_numpy_view(capture): ...@@ -242,14 +232,12 @@ def test_numpy_view(capture):
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
@pytest.requires_numpy
def test_cast_numpy_int64_to_uint64(): def test_cast_numpy_int64_to_uint64():
from pybind11_tests.array import function_taking_uint64 from pybind11_tests.array import function_taking_uint64
function_taking_uint64(123) function_taking_uint64(123)
function_taking_uint64(np.uint64(123)) function_taking_uint64(np.uint64(123))
@pytest.requires_numpy
def test_isinstance(): def test_isinstance():
from pybind11_tests.array import isinstance_untyped, isinstance_typed from pybind11_tests.array import isinstance_untyped, isinstance_typed
...@@ -257,7 +245,6 @@ def test_isinstance(): ...@@ -257,7 +245,6 @@ def test_isinstance():
assert isinstance_typed(np.array([1.0, 2.0, 3.0])) assert isinstance_typed(np.array([1.0, 2.0, 3.0]))
@pytest.requires_numpy
def test_constructors(): def test_constructors():
from pybind11_tests.array import default_constructors, converting_constructors from pybind11_tests.array import default_constructors, converting_constructors
......
import re import re
import pytest import pytest
pytestmark = pytest.requires_numpy
with pytest.suppress(ImportError): with pytest.suppress(ImportError):
import numpy as np import numpy as np
...@@ -58,7 +60,6 @@ def assert_equal(actual, expected_data, expected_dtype): ...@@ -58,7 +60,6 @@ def assert_equal(actual, expected_data, expected_dtype):
np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype)) np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype))
@pytest.requires_numpy
def test_format_descriptors(): def test_format_descriptors():
from pybind11_tests import get_format_unbound, print_format_descriptors from pybind11_tests import get_format_unbound, print_format_descriptors
...@@ -85,7 +86,6 @@ def test_format_descriptors(): ...@@ -85,7 +86,6 @@ def test_format_descriptors():
] ]
@pytest.requires_numpy
def test_dtype(simple_dtype): def test_dtype(simple_dtype):
from pybind11_tests import (print_dtypes, test_dtype_ctors, test_dtype_methods, from pybind11_tests import (print_dtypes, test_dtype_ctors, test_dtype_methods,
trailing_padding_dtype, buffer_to_dtype) trailing_padding_dtype, buffer_to_dtype)
...@@ -113,7 +113,6 @@ def test_dtype(simple_dtype): ...@@ -113,7 +113,6 @@ def test_dtype(simple_dtype):
assert trailing_padding_dtype() == buffer_to_dtype(np.zeros(1, trailing_padding_dtype())) assert trailing_padding_dtype() == buffer_to_dtype(np.zeros(1, trailing_padding_dtype()))
@pytest.requires_numpy
def test_recarray(simple_dtype, packed_dtype): def test_recarray(simple_dtype, packed_dtype):
from pybind11_tests import (create_rec_simple, create_rec_packed, create_rec_nested, from pybind11_tests import (create_rec_simple, create_rec_packed, create_rec_nested,
print_rec_simple, print_rec_packed, print_rec_nested, print_rec_simple, print_rec_packed, print_rec_nested,
...@@ -178,7 +177,6 @@ def test_recarray(simple_dtype, packed_dtype): ...@@ -178,7 +177,6 @@ def test_recarray(simple_dtype, packed_dtype):
np.testing.assert_equal(arr['a'], create_rec_partial(3)) np.testing.assert_equal(arr['a'], create_rec_partial(3))
@pytest.requires_numpy
def test_array_constructors(): def test_array_constructors():
from pybind11_tests import test_array_ctors from pybind11_tests import test_array_ctors
...@@ -191,7 +189,6 @@ def test_array_constructors(): ...@@ -191,7 +189,6 @@ def test_array_constructors():
np.testing.assert_array_equal(test_array_ctors(40 + i), data) np.testing.assert_array_equal(test_array_ctors(40 + i), data)
@pytest.requires_numpy
def test_string_array(): def test_string_array():
from pybind11_tests import create_string_array, print_string_array from pybind11_tests import create_string_array, print_string_array
...@@ -210,7 +207,6 @@ def test_string_array(): ...@@ -210,7 +207,6 @@ def test_string_array():
assert dtype == arr.dtype assert dtype == arr.dtype
@pytest.requires_numpy
def test_enum_array(): def test_enum_array():
from pybind11_tests import create_enum_array, print_enum_array from pybind11_tests import create_enum_array, print_enum_array
...@@ -227,14 +223,12 @@ def test_enum_array(): ...@@ -227,14 +223,12 @@ def test_enum_array():
assert create_enum_array(0).dtype == dtype assert create_enum_array(0).dtype == dtype
@pytest.requires_numpy
def test_signature(doc): def test_signature(doc):
from pybind11_tests import create_rec_nested from pybind11_tests import create_rec_nested
assert doc(create_rec_nested) == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" assert doc(create_rec_nested) == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
@pytest.requires_numpy
def test_scalar_conversion(): def test_scalar_conversion():
from pybind11_tests import (create_rec_simple, f_simple, from pybind11_tests import (create_rec_simple, f_simple,
create_rec_packed, f_packed, create_rec_packed, f_packed,
...@@ -256,7 +250,6 @@ def test_scalar_conversion(): ...@@ -256,7 +250,6 @@ def test_scalar_conversion():
assert 'incompatible function arguments' in str(excinfo.value) assert 'incompatible function arguments' in str(excinfo.value)
@pytest.requires_numpy
def test_register_dtype(): def test_register_dtype():
from pybind11_tests import register_dtype from pybind11_tests import register_dtype
......
import pytest import pytest
pytestmark = pytest.requires_numpy
with pytest.suppress(ImportError): with pytest.suppress(ImportError):
import numpy as np import numpy as np
@pytest.requires_numpy
def test_vectorize(capture): def test_vectorize(capture):
from pybind11_tests import vectorized_func, vectorized_func2, vectorized_func3 from pybind11_tests import vectorized_func, vectorized_func2, vectorized_func3
...@@ -58,7 +59,6 @@ def test_vectorize(capture): ...@@ -58,7 +59,6 @@ def test_vectorize(capture):
""" """
@pytest.requires_numpy
def test_type_selection(): def test_type_selection():
from pybind11_tests import selective_func from pybind11_tests import selective_func
...@@ -67,7 +67,6 @@ def test_type_selection(): ...@@ -67,7 +67,6 @@ def test_type_selection():
assert selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken." assert selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken."
@pytest.requires_numpy
def test_docs(doc): def test_docs(doc):
from pybind11_tests import vectorized_func from pybind11_tests import vectorized_func
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment