# Path: wiring/interface.py
# class Method(Attribute):
#     """
#     This class stores a specification of a method, describing its arguments and
#     holding its docstring. It is used by :py:class:`InterfaceMetaclass` to
#     store information about required methods of an :term:`interface`.
#     """
# 
#     def __init__(self, argument_specification, docstring=None):
#         super(Method, self).__init__(docstring)
#         self.argument_specification = argument_specification
#         """
#         An `inspect.ArgSpec` or `inspect.FullArgSpec` (depending on Python
#         version) named tuple specifying arguments taken by described method.
#         These will not include implied `self` argument.
#         """
# 
#     def __repr__(self):
#         return '<Method{}>'.format(
#             inspect.formatargspec(*self.argument_specification)
#         )
# 
#     def check_compliance(self, function):
#         """
#         Checks if a given `function` complies with this specification. If an
#         inconsistency is detected a :py:exc:`MethodValidationError` exception
#         is raised.
# 
#         .. note::
#             This method will not work as expected when `function` is an unbound
#             method (``SomeClass.some_method``), as in Python 3 there is no way
#             to recognize that this is in fact a method. Therefore, the implied
#             `self` argument will not be ignored.
# 
#         :raises:
#             :py:exc:`MethodValidationError`
#         """
#         argument_specification = _get_argument_specification(function)
#         if inspect.ismethod(function):
#             # Remove implied `self` argument from specification if function is
#             # a method.
#             argument_specification = argument_specification._replace(
#                 args=argument_specification.args[1:]
#             )
#         if argument_specification != self.argument_specification:
#             raise MethodValidationError(
#                 function,
#                 self.argument_specification,
#                 argument_specification
#             )
# 
# class MethodValidationError(InterfaceComplianceError):
#     """
#     Exception raised when a function is validated against :py:class:`Method`
#     specification (e.g. by :py:meth:`Interface.check_compliance`) and some of
#     the arguments differ.
#     """
# 
#     def __init__(self, function, expected_argspec, observed_argspec):
#         self.function = function
#         """
#         Function object that didn't pass the check.
#         """
#         self.expected_argspec = expected_argspec
#         """
#         An `inspect.ArgSpec` or `inspect.FullArgSpec` (depending on Python
#         version) named tuple specifying expected function arguments.
#         """
#         self.observed_argspec = observed_argspec
#         """
#         An `inspect.ArgSpec` or `inspect.FullArgSpec` (depending on Python
#         version) named tuple specifying arguments that the validated
#         function actually takes.
#         """
# 
#     def __str__(self):
#         return (
#             "Function `{function}` does not comply with interface definition."
#             " Expected arguments: {expected}"
#             " Observed arguments: {observed}"
#         ).format(
#             function=self.function.__name__,
#             expected=inspect.formatargspec(*self.expected_argspec),
#             observed=inspect.formatargspec(*self.observed_argspec)
#         )


import inspect
import unittest
import six
from wiring.interface import Method, MethodValidationError
        self.assertEqual(method.docstring, "Some docstring.")

    def test_repr(self):
        argspec = self._get_argspec()

        method = Method(argspec)
        self.assertEqual(repr(method), '<Method(foo, bar=12, *, foobar)>')

        method = Method(argspec, docstring="Some docstring.")
        self.assertEqual(repr(method), '<Method(foo, bar=12, *, foobar)>')

    def test_check_compliance(self):
        argspec = self._get_argspec()

        method = Method(argspec)
        method.check_compliance(self._example_method_implementation)
        method.check_compliance(self._example_method_classmethod)
        method.check_compliance(self._example_method_static)

        def other_implementation(foo, bar=12, *, foobar):
            pass
        method.check_compliance(other_implementation)

        def invalid_implementation1(foo, bar=12):
            pass
        with self.assertRaises(MethodValidationError):
            method.check_compliance(invalid_implementation1)

        def invalid_implementation2(foo, bar=13, *, foobar):
            pass

# Path: wiring/interface.py
# class Method(Attribute):
#     """
#     This class stores a specification of a method, describing its arguments and
#     holding its docstring. It is used by :py:class:`InterfaceMetaclass` to
#     store information about required methods of an :term:`interface`.
#     """
# 
#     def __init__(self, argument_specification, docstring=None):
#         super(Method, self).__init__(docstring)
#         self.argument_specification = argument_specification
#         """
#         An `inspect.ArgSpec` or `inspect.FullArgSpec` (depending on Python
#         version) named tuple specifying arguments taken by described method.
#         These will not include implied `self` argument.
#         """
# 
#     def __repr__(self):
#         return '<Method{}>'.format(
#             inspect.formatargspec(*self.argument_specification)
#         )
# 
#     def check_compliance(self, function):
#         """
#         Checks if a given `function` complies with this specification. If an
#         inconsistency is detected a :py:exc:`MethodValidationError` exception
#         is raised.
# 
#         .. note::
#             This method will not work as expected when `function` is an unbound
#             method (``SomeClass.some_method``), as in Python 3 there is no way
#             to recognize that this is in fact a method. Therefore, the implied
#             `self` argument will not be ignored.
# 
#         :raises:
#             :py:exc:`MethodValidationError`
#         """
#         argument_specification = _get_argument_specification(function)
#         if inspect.ismethod(function):
#             # Remove implied `self` argument from specification if function is
#             # a method.
#             argument_specification = argument_specification._replace(
#                 args=argument_specification.args[1:]
#             )
#         if argument_specification != self.argument_specification:
#             raise MethodValidationError(
#                 function,
#                 self.argument_specification,
#                 argument_specification
#             )
# 
# class MethodValidationError(InterfaceComplianceError):
#     """
#     Exception raised when a function is validated against :py:class:`Method`
#     specification (e.g. by :py:meth:`Interface.check_compliance`) and some of
#     the arguments differ.
#     """
# 
#     def __init__(self, function, expected_argspec, observed_argspec):
#         self.function = function
#         """
#         Function object that didn't pass the check.
#         """
#         self.expected_argspec = expected_argspec
#         """
#         An `inspect.ArgSpec` or `inspect.FullArgSpec` (depending on Python
#         version) named tuple specifying expected function arguments.
#         """
#         self.observed_argspec = observed_argspec
#         """
#         An `inspect.ArgSpec` or `inspect.FullArgSpec` (depending on Python
#         version) named tuple specifying arguments that the validated
#         function actually takes.
#         """
# 
#     def __str__(self):
#         return (
#             "Function `{function}` does not comply with interface definition."
#             " Expected arguments: {expected}"
#             " Observed arguments: {observed}"
#         ).format(
#             function=self.function.__name__,
#             expected=inspect.formatargspec(*self.expected_argspec),
#             observed=inspect.formatargspec(*self.observed_argspec)
#         )


# Path: tests/py3/interface_tests.py
import inspect
import unittest
import six
from wiring.interface import Method, MethodValidationError

        self.assertEqual(method.docstring, "Some docstring.")

    def test_repr(self):
        argspec = self._get_argspec()

        method = Method(argspec)
        self.assertEqual(repr(method), '<Method(foo, bar=12, *, foobar)>')

        method = Method(argspec, docstring="Some docstring.")
        self.assertEqual(repr(method), '<Method(foo, bar=12, *, foobar)>')

    def test_check_compliance(self):
        argspec = self._get_argspec()

        method = Method(argspec)
        method.check_compliance(self._example_method_implementation)
        method.check_compliance(self._example_method_classmethod)
        method.check_compliance(self._example_method_static)

        def other_implementation(foo, bar=12, *, foobar):
            pass
        method.check_compliance(other_implementation)

        def invalid_implementation1(foo, bar=12):
            pass
        with self.assertRaises(MethodValidationError):
            method.check_compliance(invalid_implementation1)

        def invalid_implementation2(foo, bar=13, *, foobar):
            pass

        with self.assertRaises(MethodValidationError):