duck typed estimators fail in check_estimator

### Describe the bug

I believe these 5 lines, which check for specific types:

https://github.com/scikit-learn/scikit-learn/blob/76ae0a539a0e87145c9f6fedcd7033494082fa17/sklearn/utils/estimator_checks.py#L4439-L4443

breaks the documentation in https://scikit-learn.org/stable/developers/develop.html#rolling-your-own-estimator

Where it says "We tend to use “duck typing” instead of checking for isinstance, which means it’s technically possible to implement estimator without inheriting from scikit-learn classes."

Since \_\_sklearn\_tags\_\_ appears to now be a requirement, and if those specific Tag classes are required to be returned from \_\_sklearn\_tags\_\_, then it is no longer possible to implement scikit-learn estimators through duck typing.  I believe either the tests should be changed, or the documentation updated.  I would prefer the tests to change.

### Steps/Code to Reproduce

see above

### Expected Results

see above

### Actual Results

see above

### Versions

```shell
1.6.0
```

COMMENT:
@glemaitre, the main benefit in using duck typing is to limit import dependencies and by doing that improve package reliability.  Currently InterpretML has a dependency on scikit-learn, but my longer-term goal is to eliminate this dependency.  scikit-learn is thankfully a generally reliable package (thanks to you and other contributors), however new releases can still cause problems, as evidenced by the 1.6 release (see https://github.com/interpretml/interpret/issues/589).  I blame myself of course for any issues in InterpretML, however it's still a scenario that could be improved upon by eliminating the dependency.

I note that XGBoost has a similar mechanism.  They have a neat trick where they inherit optionally from BaseEstimator and substitute their own classes when scikit-learn is not installed.  I'll probably copy this inheritance scheme at some point:

https://github.com/dmlc/xgboost/blob/master/python-package/xgboost/compat.py#L66-L79

In terms of feedback, I foresee that the current tag system is going to make avoiding imports a higher maintenance activity for packages like XGBoost and InterpretML going forward.  The original tag system that used dictionaries allowed for tags to not exist, with non-existence being the equivalent of False.  In the new class-based scheme it appears the expectation is that all tags will exists.  When new releases of scikit-learn occur, packages that use duck typing will not have any of the newer tags, and might therefore fail when intermixed with other scikit-learn classes.  That's one of the reasons I might copy the XGBoost model of inheriting from BaseEstimator when scikit-learn is installed, because then inheritance will ensure the new attributes will exist even if the dependent package was released before scikit-learn.

In terms of maintaining compatibility, it would be useful to use check_estimator to at least know when there are new tags, however since that check doesn't work with duck typing, I can't use it.  I'll probably write a test that will check my classes vs the scikit-learn ones, and that test will be expected to fail when new scikit-learn releases occur.

Labels: Bug