codecov[bot]: # [Codecov](https://codecov.io/gh/ESSS/oop-ext/pull/23?src=pr&el=h1) Report
> Merging [#23](https://codecov.io/gh/ESSS/oop-ext/pull/23?src=pr&el=desc) into [master](https://codecov.io/gh/ESSS/oop-ext/commit/a6b298e39a84fdc2344ca36857d3e31a0b741b29?src=pr&el=desc) will **increase** coverage by `0.03%`.
> The diff coverage is `100%`.


```diff
@@            Coverage Diff             @@
##           master      #23      +/-   ##
==========================================
+ Coverage   95.56%   95.59%   +0.03%     
==========================================
  Files          32       32              
  Lines        3225     3226       +1     
==========================================
+ Hits         3082     3084       +2     
+ Misses        143      142       -1
```

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 41e5a14..0de729f 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,6 +1,11 @@
-0.5.1 (2019-12-20)
+0.6.0 (2020-01-31)
 ==================
 
+* Change back the default value of ``requires_declaration`` to ``True`` and fix an error (#22) where the cache wasn 't properly cleared.
+
+0.5.1 (2019-12-20)
+------------------
+
 * Fixes an issue (#20) where mocked `classmethods` weren't considered a valid method during internal checks.
 
 0.5.0 (2019-12-12)
diff --git a/src/oop_ext/interface/_interface.py b/src/oop_ext/interface/_interface.py
index 5fd1ffa..d87f910 100644
--- a/src/oop_ext/interface/_interface.py
+++ b/src/oop_ext/interface/_interface.py
@@ -191,7 +191,7 @@ def _IsClass(obj):
     return isinstance(obj, type)
 
 
-def IsImplementation(class_or_instance, interface, *, requires_declaration=False):
+def IsImplementation(class_or_instance, interface, *, requires_declaration=True):
     """
     :type class_or_instance: type or classobj or object
 
@@ -199,9 +199,11 @@ def IsImplementation(class_or_instance, interface, *, requires_declaration=False
 
     :type requires_declaration: bool
         If `True`, the Interface must have been explicitly declared through :py:func:`ImplementsInterface`
-        for `class_or_interface` to be considered an implementation of `interface`. Alternatively, it's
-        possible to use :py:func:`DeclareClassImplements` from outside the class in order to tell that
-        interfaces are implemented.
+        for `class_or_interface` to be considered an implementation of `interface`. Otherwise it'd only
+        check if `class_or_interface` has all methods defined on `interface`.
+        Note that `class_or_instance` attributes are never evaluated.
+        Alternatively, it's possible to use :py:func:`DeclareClassImplements` from outside the class in
+        order to tell which interfaces are implemented.
 
     :rtype: bool
 
@@ -225,7 +227,7 @@ def IsImplementation(class_or_instance, interface, *, requires_declaration=False
     return is_implementation
 
 
-def IsImplementationOfAny(class_or_instance, interfaces, *, requires_declaration=False):
+def IsImplementationOfAny(class_or_instance, interfaces, *, requires_declaration=True):
     """
     Check if the class or instance implements any of the given interfaces
 
@@ -252,7 +254,7 @@ def IsImplementationOfAny(class_or_instance, interfaces, *, requires_declaration
     return False
 
 
-def AssertImplements(class_or_instance, interface, *, requires_declaration=False):
+def AssertImplements(class_or_instance, interface, *, requires_declaration=True):
     """
     If given a class, will try to match the class against a given interface. If given an object
     (instance), will try to match the class of the given object.
@@ -309,7 +311,7 @@ __ImplementsCache = __ResultsCache()
 __ImplementedInterfacesCache = __ResultsCache()
 
 
-def _CheckIfClassImplements(class_, interface, *, requires_declaration=False):
+def _CheckIfClassImplements(class_, interface, *, requires_declaration=True):
     """
     :type class_: type or classobj
     :param class_:
@@ -863,10 +865,11 @@ def DeclareClassImplements(class_, *interfaces):
     try:
         for interface in interfaces:
             # Forget any previous checks
-            __ImplementsCache.ForgetResult((class_, interface))
+            __ImplementsCache.ForgetResult((class_, interface, False))
+            __ImplementsCache.ForgetResult((class_, interface, True))
             __ImplementedInterfacesCache.ForgetResult(class_)
 
-            AssertImplements(class_, interface)
+            AssertImplements(class_, interface, requires_declaration=False)
     except:
         # Roll back...
         class_.__implements__ = old_implements

Use `requires_declaration=True` as default in `IsImplementation`
As discussed in our meeting today with @nicoddemus, @tigarmo and @igortg we need to change back the default for `requires_declaration=True` because in the current state (`False`) provides "duck typing" interfaces, that is, a given class is considered an implementation of a given interface just because it contains the same methods. That brings problems in places where the interfaces are used as IDs, we don't just need objects that have X, Y and Z methods, besides that, we need objects that explicitly declared which interfaces were implemented.
diff --git a/src/oop_ext/interface/_tests/test_interface.py b/src/oop_ext/interface/_tests/test_interface.py
index 8beb611..737a454 100644
--- a/src/oop_ext/interface/_tests/test_interface.py
+++ b/src/oop_ext/interface/_tests/test_interface.py
@@ -72,7 +72,7 @@ def testBasics():
 
     assert IsImplementation(C, I) == True  # OK
     # C2 shouldn't need to declare `@ImplementsInterface(I)`
-    assert IsImplementation(C2, I) == True
+    assert IsImplementation(C2, I, requires_declaration=False) == True
     assert IsImplementation(C2, I, requires_declaration=True) == False
     assert not IsImplementation(D, I) == True  # nope
 
@@ -87,7 +87,9 @@ def testBasics():
     # Now declare that C2 implements I
     DeclareClassImplements(C2, I)
 
-    assert IsImplementation(C2, I) == True  # Does not declare
+    assert (
+        IsImplementation(C2, I, requires_declaration=True) == True
+    )  # Even if it doesn't declare
 
 
 def testMissingMethod():
@@ -514,12 +516,16 @@ def testAdaptableInterface():
 
 
 def testNull():
-    AssertImplements(Null(), _InterfM2)  # Not raises BadImplementationError
+    AssertImplements(
+        Null(), _InterfM2, requires_declaration=False
+    )  # Not raises BadImplementationError
 
     class ExtendedNull(Null):
         ""
 
-    AssertImplements(ExtendedNull(), _InterfM2)  # Not raises BadImplementationError
+    AssertImplements(
+        ExtendedNull(), _InterfM2, requires_declaration=False
+    )  # Not raises BadImplementationError
 
 
 def testSetItem():
@@ -575,7 +581,7 @@ def testImplementorWithAny():
         def m3(self, *args, **kwargs):
             ""
 
-    AssertImplements(M3(), _InterfM3)
+    AssertImplements(M3(), _InterfM3, requires_declaration=False)
 
 
 def testInterfaceCheckRequiresInterface():
@@ -687,7 +693,7 @@ def testDeclareClassImplements():
     with pytest.raises(AssertionError):
         DeclareClassImplements(C0, I1)
 
-    assert IsImplementation(C1, I1) == True
+    assert IsImplementation(C1, I1, requires_declaration=False) == True
 
     DeclareClassImplements(C1, I1)
 
@@ -881,9 +887,13 @@ def testIsImplementationOfAny():
             ""
 
     a_obj = A()
-    AssertImplements(a_obj, _InterfM3)
-    assert IsImplementationOfAny(A, [_InterfM1, _InterfM2, _InterfM3, _InterfM4])
-    assert not IsImplementationOfAny(A, [_InterfM1, _InterfM2, _InterfM4])
+    AssertImplements(a_obj, _InterfM3, requires_declaration=False)
+    assert IsImplementationOfAny(
+        A, [_InterfM1, _InterfM2, _InterfM3, _InterfM4], requires_declaration=False
+    )
+    assert not IsImplementationOfAny(
+        A, [_InterfM1, _InterfM2, _InterfM4], requires_declaration=False
+    )
 
 
 def testClassMethodBug(mocker):

pip install -e .[testing,docs]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-mock pre_commit
3.9
requirements/base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
babel==2.17.0
cachetools==5.5.2
certifi==2025.1.31
cfgv==3.4.0
chardet==5.2.0
charset-normalizer==3.4.1
codecov==2.1.13
colorama==0.4.6
coverage==7.8.0
distlib==0.3.9
docutils==0.21.2
exceptiongroup==1.2.2
filelock==3.18.0
identify==2.6.9
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
Jinja2==3.1.6
MarkupSafe==3.0.2
nodeenv==1.9.1
-e git+https://github.com/ESSS/oop-ext.git@a6b298e39a84fdc2344ca36857d3e31a0b741b29#egg=oop_ext
packaging==24.2
platformdirs==4.3.7
pluggy==1.5.0
pre_commit==4.2.0
Pygments==2.19.1
pyproject-api==1.9.0
pytest==8.3.5
pytest-cov==6.0.0
pytest-mock==3.14.0
PyYAML==6.0.2
requests==2.32.3
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinx-autodoc-typehints==2.3.0
sphinx-rtd-theme==3.0.2
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
tomli==2.2.1
tox==4.25.0
typing_extensions==4.13.0
urllib3==2.3.0
virtualenv==20.29.3
zipp==3.21.0

name: oop-ext
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - babel==2.17.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - cfgv==3.4.0
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - codecov==2.1.13
      - colorama==0.4.6
      - coverage==7.8.0
      - distlib==0.3.9
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - filelock==3.18.0
      - identify==2.6.9
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - nodeenv==1.9.1
      - packaging==24.2
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pre-commit==4.2.0
      - pygments==2.19.1
      - pyproject-api==1.9.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - pyyaml==6.0.2
      - requests==2.32.3
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinx-autodoc-typehints==2.3.0
      - sphinx-rtd-theme==3.0.2
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - tomli==2.2.1
      - tox==4.25.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - virtualenv==20.29.3
      - zipp==3.21.0
prefix: /opt/conda/envs/oop-ext

src/oop_ext/interface/_tests/test_interface.py::testBasics
src/oop_ext/interface/_tests/test_interface.py::testMissingMethod src/oop_ext/interface/_tests/test_interface.py::testSubclasses src/oop_ext/interface/_tests/test_interface.py::testSubclasses2 src/oop_ext/interface/_tests/test_interface.py::testNoName src/oop_ext/interface/_tests/test_interface.py::testAttributes src/oop_ext/interface/_tests/test_interface.py::testPassNoneInAssertImplementsFullChecking src/oop_ext/interface/_tests/test_interface.py::testNoCheck src/oop_ext/interface/_tests/test_interface.py::testCallbackAndInterfaces src/oop_ext/interface/_tests/test_interface.py::testInterfaceStubFromClasses src/oop_ext/interface/_tests/test_interface.py::testStubsFromInstances src/oop_ext/interface/_tests/test_interface.py::testIsImplementationWithSubclasses src/oop_ext/interface/_tests/test_interface.py::testIsImplementationWithBuiltInObjects src/oop_ext/interface/_tests/test_interface.py::testClassImplementMethod src/oop_ext/interface/_tests/test_interface.py::testGetImplementedInterfaces src/oop_ext/interface/_tests/test_interface.py::testGetImplementedInterfaces2 src/oop_ext/interface/_tests/test_interface.py::testAdaptableInterface src/oop_ext/interface/_tests/test_interface.py::testNull src/oop_ext/interface/_tests/test_interface.py::testSetItem src/oop_ext/interface/_tests/test_interface.py::testAssertImplementsDoesNotDirObject src/oop_ext/interface/_tests/test_interface.py::testImplementorWithAny src/oop_ext/interface/_tests/test_interface.py::testInterfaceCheckRequiresInterface src/oop_ext/interface/_tests/test_interface.py::testReadOnlyAttribute src/oop_ext/interface/_tests/test_interface.py::testReadOnlyAttributeMissingImplementation src/oop_ext/interface/_tests/test_interface.py::testImplementsTwice src/oop_ext/interface/_tests/test_interface.py::testDeclareClassImplements src/oop_ext/interface/_tests/test_interface.py::testCallableInterfaceStub src/oop_ext/interface/_tests/test_interface.py::testImplementsInterfaceAsBoolError src/oop_ext/interface/_tests/test_interface.py::test_interface_subclass_mocked[True-True] src/oop_ext/interface/_tests/test_interface.py::test_interface_subclass_mocked[True-False] src/oop_ext/interface/_tests/test_interface.py::test_interface_subclass_mocked[False-True] src/oop_ext/interface/_tests/test_interface.py::test_interface_subclass_mocked[False-False] src/oop_ext/interface/_tests/test_interface.py::testErrorOnInterfaceDeclaration src/oop_ext/interface/_tests/test_interface.py::testKeywordOnlyArguments src/oop_ext/interface/_tests/test_interface.py::testHashableArgumentsInterface src/oop_ext/interface/_tests/test_interface.py::testHashableArgumentsImplementation src/oop_ext/interface/_tests/test_interface.py::testIsImplementationOfAny src/oop_ext/interface/_tests/test_interface.py::testClassMethodBug
CHANGELOG.rst src/oop_ext/interface/_interface.py
CHANGELOG.rst src/oop_ext/interface/_interface.py