@@ -60,9 +60,7 @@ def doc_only_run(self):
60
60
docstring = list (node .findall (condition = desc_content ))
61
61
62
62
if not docstring :
63
- logger .warning (
64
- f"The docstring for { self .arguments [0 ]} cannot be found."
65
- )
63
+ logger .warning (f"The docstring for { self .arguments [0 ]} cannot be found." )
66
64
return []
67
65
68
66
return docstring
@@ -100,99 +98,38 @@ def no_doc_run(self):
100
98
# replacements will be performed globally. Hyperlinks will be added in the
101
99
# signature if "good type" is a valid (potentially user defined) python type
102
100
type_replacements = {
103
- (
104
- r"libsemigroups::Presentation<std::__cxx11::basic_string<char, "
105
- r"std::char_traits<char>, std::allocator<char> > >"
106
- ): r"Presentation" ,
107
- r"libsemigroups::BMat8" : r"BMat8" ,
108
101
r"libsemigroups::WordGraph<unsigned int>" : r"WordGraph" ,
109
- r"libsemigroups::Gabow<unsigned int>" : r"Gabow" ,
110
- (
111
- r"libsemigroups::DynamicMatrix<libsemigroups::IntegerPlus<long long>, "
112
- r"libsemigroups::IntegerProd<long long>, libsemigroups::IntegerZero"
113
- r"<long long>, libsemigroups::IntegerOne<long long>, long long>"
114
- ): r"Matrix" ,
115
102
r"libsemigroups::SimsStats" : r"SimsStats" ,
116
103
r"libsemigroups::Sims1" : r"Sims1" ,
117
104
r"libsemigroups::Sims2" : r"Sims2" ,
118
105
r"libsemigroups::RepOrc" : r"RepOrc" ,
119
106
r"libsemigroups::MinimalRepOrc" : r"MinimalRepOrc" ,
120
- (
121
- r"libsemigroups::DynamicMatrix<libsemigroups::BooleanPlus, "
122
- r"libsemigroups::BooleanProd, libsemigroups::BooleanZero, "
123
- r"libsemigroups::BooleanOne, int>"
124
- ): r"Matrix" ,
125
- r"libsemigroups::Konieczny<BMat8, "
126
- "libsemigroups::KoniecznyTraits<BMat8>>::DClass" : "KoniecznyBMat8DClass" ,
127
107
}
128
108
129
109
# This dictionary should be of the form class_name -> (pattern, repl), where
130
110
# "pattern" should be replaced by "repl" in the signature of all functions in
131
111
# "class_name"
132
112
class_specific_replacements = {
133
- "RightActionPPerm1List" : [
134
- ("libsemigroups::PPerm<16ul, unsigned char>" , "Element" ),
135
- ("libsemigroups::Element" , "Element" ),
136
- ("libsemigroups::PPerm<0ul, unsigned char>" , "Element" ),
137
- ],
138
- "Transf1" : [
139
- ("PTransfBase1" , "Transf1" ),
140
- ],
141
- "PPerm1" : [
142
- ("PTransfBase1" , "PPerm1" ),
143
- ],
144
- "Perm1" : [
145
- ("PTransfBase1" , "Perm1" ),
146
- ("Transf" , "Perm" ),
147
- ],
148
- "FroidurePinPBR" : [(r"\bPBR\b" , "Element" )],
149
- "SchreierSimsPerm1" : [(r"\bPerm1\b" , "Element" )],
150
113
"Sims1" : [("SubclassType" , "Sims1" ), ("SimsSettingsSims1" , "Sims1" )],
151
114
"Sims2" : [("SubclassType" , "Sims2" ), ("SimsSettingsSims2" , "Sims2" )],
152
115
"MinimalRepOrc" : [
153
116
("SubclassType" , "MinimalRepOrc" ),
154
117
("SimsSettingsMinimalRepOrc" , "MinimalRepOrc" ),
155
- (r"\bRepOrc\b" , "MinimalRepOrc" ),
156
118
],
157
119
"RepOrc" : [
158
120
("SubclassType" , "RepOrc" ),
159
121
("SimsSettingsRepOrc" , "RepOrc" ),
160
122
],
161
- "KoniecznyBMat8" : [
162
- (r"\bBMat8\b" , "Element" ),
163
- (
164
- "libsemigroups::Konieczny<libsemigroups::Element, "
165
- "libsemigroups::KoniecznyTraits<libsemigroups::Element>>::DClass" ,
166
- "KoniecznyBMat8.DClass" ,
167
- ),
168
- ],
169
123
}
170
124
171
125
# This dictionary should be of the form bad_string -> good_string. These
172
126
# replacements will be made in each docstring, and will be useful for removing
173
127
# things like the signatures that sphinx inserts into every docstring
174
- docstring_replacements = {
175
- r"_current_index_of.*$" : "" ,
176
- r"_number_of_classes.*$" : "" ,
177
- r"_small_overlap_class.*$" : "" ,
178
- r"aho_corasick_dot\(.*\)(\s*->\s*(\w+::)*\w*)?" : "" ,
179
- r"congruence_non_trivial_classes.*$" : "" ,
180
- r"congruence_partition.*$" : "" ,
181
- r"kambites_normal_forms.*$" : "" ,
182
- r"knuth_bendix_non_trivial_classes.*$" : "" ,
183
- r"pbr_one\(\*args, \*\*kwargs\)" : "" ,
184
- r"todd_coxeter_is_non_trivial.*$" : "" ,
185
- r"todd_coxeter_non_trivial_class.*$" : "" ,
186
- r"todd_coxeter_normal_forms.*$" : "" ,
187
- r"todd_coxeter_partition.*$" : "" ,
188
- r"todd_coxeter_redundant_rule.*$" : "" ,
189
- r"word_graph_dot\(.*\)(\s*->\s*(\w+::)*\w*)?" : "" ,
190
- r"D_class_of_element\(.*$" : "" ,
191
- }
128
+ docstring_replacements = {}
192
129
193
130
194
131
# This is what sphinx considers to be a signature
195
- signature_re = re .compile (
132
+ custom_signature_re = re .compile (
196
133
r""":sig=([\w.]+::)? # explicit module name
197
134
([\w.]+\.)? # module and/or class name(s)
198
135
(?:(\w+) \s*)? # thing name
@@ -202,6 +139,16 @@ def no_doc_run(self):
202
139
re .VERBOSE ,
203
140
)
204
141
142
+ inserted_signature_re = re .compile (
143
+ r"""^([\w.]+::)? # explicit module name
144
+ ([\w.]+\.)? # module and/or class name(s)
145
+ (?:(\w+) \s*)? # thing name
146
+ (?: \[\s*(.*)\s*\])? # type parameters list
147
+ (?: \((.*)\))? # arguments
148
+ (?:\s* -> \s* (.*))?$""" , # return annotation
149
+ re .VERBOSE | re .MULTILINE ,
150
+ )
151
+
205
152
206
153
def sub_if_not_none (pattern , repl , * strings ):
207
154
"""Make regex replacement on inputs that are not None"""
@@ -222,14 +169,19 @@ def sub_if_not_none(pattern, repl, *strings):
222
169
def sig_alternative (doc , signature , return_annotation ):
223
170
"""Find an alternative signature defined in the docstring
224
171
225
- If there is not exactly one signature set using :sig=...:, then no changes
226
- occur.
172
+ If there is no signature specified using :sig=...:, then no changes occur.
173
+ If multiple different signatures are specified using :sig=...:, then the
174
+ signature is set to (*args, **kwargs). Otherwise, the signature is set to
175
+ the unique signature specified using :sig=...:.
227
176
"""
228
177
if not doc :
229
178
return signature , return_annotation
230
- m = set (re .findall (signature_re , doc ))
231
- if len (m ) != 1 :
179
+
180
+ m = set (re .findall (custom_signature_re , doc ))
181
+ if len (m ) == 0 :
232
182
return signature , return_annotation
183
+ if len (m ) > 1 :
184
+ return "(*args, **kwargs)" , ""
233
185
234
186
_ , _ , _ , _ , args , return_annotation = m .pop ()
235
187
new_sig = f"({ args } )"
@@ -368,7 +320,7 @@ def fix_overloads(app, what, name, obj, options, lines):
368
320
# Capture the initial indent and the function signature
369
321
new_sig = False
370
322
if i + 3 < len (input_text ):
371
- m = re .match (signature_re , input_text [i + 3 ])
323
+ m = re .match (custom_signature_re , input_text [i + 3 ])
372
324
if m is not None :
373
325
new_sig = True
374
326
_ , _ , _ , _ , args , return_annotation = m .groups ()
@@ -403,6 +355,17 @@ def fix_overloads(app, what, name, obj, options, lines):
403
355
404
356
def remove_doc_annotations (app , what , name , obj , options , lines ):
405
357
"""Remove any special decorations from the documentation"""
358
+ if len (lines ) == 0 :
359
+ return
360
+
361
+ # Remove inserted signatures if they have the wrong name
362
+ m = re .match (inserted_signature_re , lines [0 ])
363
+ if m :
364
+ specified_name = m [3 ]
365
+ short_name = name .split ("." )[- 1 ]
366
+ if short_name != specified_name :
367
+ del lines [0 ]
368
+
406
369
for i in range (len (lines ) - 1 , - 1 , - 1 ):
407
370
for bad , good in docstring_replacements .items ():
408
371
lines [i ], n = re .subn (bad , good , lines [i ])
@@ -443,8 +406,10 @@ def check_string_replacements(app, env):
443
406
return
444
407
445
408
# Check which replacements were not used
409
+ any_warnings = False
446
410
for bad_type , good_type in type_replacements .items ():
447
411
if bad_type not in strings_replaced :
412
+ any_warnings = True
448
413
logger .warning (
449
414
f'"{ bad_type } " -> "{ good_type } "' ,
450
415
type = "unused-replacement" ,
@@ -453,17 +418,20 @@ def check_string_replacements(app, env):
453
418
for class_name , repls in class_specific_replacements .items ():
454
419
for pattern , repl in repls :
455
420
if pattern not in strings_replaced :
421
+ any_warnings = True
456
422
logger .warning (
457
423
f'"{ pattern } " -> "{ repl } " in { class_name } ' ,
458
424
type = "unused-replacement" ,
459
425
)
460
426
for bad_string , good_string in docstring_replacements .items ():
461
427
if bad_string not in strings_replaced :
428
+ any_warnings = True
462
429
logger .warning (
463
430
f'"{ bad_string } " -> "{ good_string } "' ,
464
431
type = "unused-replacement" ,
465
432
)
466
- logger .info (f"Please correct this in { __file__ } " )
433
+ if any_warnings :
434
+ logger .info (f"Please correct this in { __file__ } " )
467
435
468
436
469
437
def setup (app ):
0 commit comments