Ensure basic interface compliance for an instance or dict of callables. Checks that ``obj`` implements public methods of ``cls`` or has members listed in ``methods``. If ``required`` is not supplied, implementing at least one interface method is sufficient. Methods present on ``obj`` th
(obj, cls=None, methods=None, required=None)
| 1053 | |
| 1054 | |
| 1055 | def as_interface(obj, cls=None, methods=None, required=None): |
| 1056 | """Ensure basic interface compliance for an instance or dict of callables. |
| 1057 | |
| 1058 | Checks that ``obj`` implements public methods of ``cls`` or has members |
| 1059 | listed in ``methods``. If ``required`` is not supplied, implementing at |
| 1060 | least one interface method is sufficient. Methods present on ``obj`` that |
| 1061 | are not in the interface are ignored. |
| 1062 | |
| 1063 | If ``obj`` is a dict and ``dict`` does not meet the interface |
| 1064 | requirements, the keys of the dictionary are inspected. Keys present in |
| 1065 | ``obj`` that are not in the interface will raise TypeErrors. |
| 1066 | |
| 1067 | Raises TypeError if ``obj`` does not meet the interface criteria. |
| 1068 | |
| 1069 | In all passing cases, an object with callable members is returned. In the |
| 1070 | simple case, ``obj`` is returned as-is; if dict processing kicks in then |
| 1071 | an anonymous class is returned. |
| 1072 | |
| 1073 | obj |
| 1074 | A type, instance, or dictionary of callables. |
| 1075 | cls |
| 1076 | Optional, a type. All public methods of cls are considered the |
| 1077 | interface. An ``obj`` instance of cls will always pass, ignoring |
| 1078 | ``required``.. |
| 1079 | methods |
| 1080 | Optional, a sequence of method names to consider as the interface. |
| 1081 | required |
| 1082 | Optional, a sequence of mandatory implementations. If omitted, an |
| 1083 | ``obj`` that provides at least one interface method is considered |
| 1084 | sufficient. As a convenience, required may be a type, in which case |
| 1085 | all public methods of the type are required. |
| 1086 | |
| 1087 | """ |
| 1088 | if not cls and not methods: |
| 1089 | raise TypeError("a class or collection of method names are required") |
| 1090 | |
| 1091 | if isinstance(cls, type) and isinstance(obj, cls): |
| 1092 | return obj |
| 1093 | |
| 1094 | interface = set(methods or [m for m in dir(cls) if not m.startswith("_")]) |
| 1095 | implemented = set(dir(obj)) |
| 1096 | |
| 1097 | complies = operator.ge |
| 1098 | if isinstance(required, type): |
| 1099 | required = interface |
| 1100 | elif not required: |
| 1101 | required = set() |
| 1102 | complies = operator.gt |
| 1103 | else: |
| 1104 | required = set(required) |
| 1105 | |
| 1106 | if complies(implemented.intersection(interface), required): |
| 1107 | return obj |
| 1108 | |
| 1109 | # No dict duck typing here. |
| 1110 | if not isinstance(obj, dict): |
| 1111 | qualifier = complies is operator.gt and "any of" or "all of" |
| 1112 | raise TypeError( |
nothing calls this directly
no test coverage detected