|
1 | 1 | import sys |
2 | 2 | import types |
3 | | -import inspect |
4 | 3 | import keyword |
5 | 4 | import itertools |
6 | 5 | import annotationlib |
7 | 6 | import abc |
8 | 7 | from reprlib import recursive_repr |
9 | 8 | lazy import copy |
| 9 | +lazy import inspect |
10 | 10 | lazy import re |
11 | 11 |
|
12 | 12 |
|
@@ -988,6 +988,28 @@ def _hash_exception(cls, fields, func_builder): |
988 | 988 | # See https://bugs.python.org/issue32929#msg312829 for an if-statement |
989 | 989 | # version of this table. |
990 | 990 |
|
| 991 | +# A non-data descriptor to autogenerate class docstring |
| 992 | +# from the signature of its __init__ method on demand. |
| 993 | +# The primary reason is to be able to lazy import `inspect` module. |
| 994 | +class _AutoDocstring: |
| 995 | + |
| 996 | + def __get__(self, _obj, cls): |
| 997 | + try: |
| 998 | + # In some cases fetching a signature is not possible. |
| 999 | + # But, we surely should not fail in this case. |
| 1000 | + text_sig = str(inspect.signature( |
| 1001 | + cls, |
| 1002 | + annotation_format=annotationlib.Format.FORWARDREF, |
| 1003 | + )).replace(' -> None', '') |
| 1004 | + except TypeError, ValueError: |
| 1005 | + text_sig = '' |
| 1006 | + |
| 1007 | + doc = cls.__name__ + text_sig |
| 1008 | + setattr(cls, '__doc__', doc) |
| 1009 | + return doc |
| 1010 | + |
| 1011 | +_auto_docstring = _AutoDocstring() |
| 1012 | + |
991 | 1013 |
|
992 | 1014 | def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen, |
993 | 1015 | match_args, kw_only, slots, weakref_slot): |
@@ -1215,23 +1237,13 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen, |
1215 | 1237 | if hash_action: |
1216 | 1238 | cls.__hash__ = hash_action(cls, field_list, func_builder) |
1217 | 1239 |
|
1218 | | - # Generate the methods and add them to the class. This needs to be done |
1219 | | - # before the __doc__ logic below, since inspect will look at the __init__ |
1220 | | - # signature. |
| 1240 | + # Generate the methods and add them to the class. |
1221 | 1241 | func_builder.add_fns_to_class(cls) |
1222 | 1242 |
|
1223 | 1243 | if not getattr(cls, '__doc__'): |
1224 | | - # Create a class doc-string. |
1225 | | - try: |
1226 | | - # In some cases fetching a signature is not possible. |
1227 | | - # But, we surely should not fail in this case. |
1228 | | - text_sig = str(inspect.signature( |
1229 | | - cls, |
1230 | | - annotation_format=annotationlib.Format.FORWARDREF, |
1231 | | - )).replace(' -> None', '') |
1232 | | - except (TypeError, ValueError): |
1233 | | - text_sig = '' |
1234 | | - cls.__doc__ = (cls.__name__ + text_sig) |
| 1244 | + # Create a class doc-string lazily via descriptor protocol |
| 1245 | + # to avoid importing `inspect` module. |
| 1246 | + cls.__doc__ = _auto_docstring |
1235 | 1247 |
|
1236 | 1248 | if match_args: |
1237 | 1249 | # I could probably compute this once. |
@@ -1391,8 +1403,10 @@ def _add_slots(cls, is_frozen, weakref_slot, defined_fields): |
1391 | 1403 | # make an update, since all closures for a class will share a |
1392 | 1404 | # given cell. |
1393 | 1405 | for member in newcls.__dict__.values(): |
| 1406 | + |
1394 | 1407 | # If this is a wrapped function, unwrap it. |
1395 | | - member = inspect.unwrap(member) |
| 1408 | + if not isinstance(member, type) and hasattr(member, '__wrapped__'): |
| 1409 | + member = inspect.unwrap(member) |
1396 | 1410 |
|
1397 | 1411 | if isinstance(member, types.FunctionType): |
1398 | 1412 | if _update_func_cell_for__class__(member, cls, newcls): |
|
0 commit comments