OpenAttack
/
build-doc.py
300 строк · 10.8 Кб
1import os2import OpenAttack3
4def getSubClasses(module, clss):5ret = []6for name in dir(module):7try:8if issubclass(module.__dict__[name], clss):9ret.append(name)10except TypeError:11continue12return ret13
14def getDocMembers(clss):15ret = []16for kw in dir(clss):17if kw.startswith("_"):18continue19if clss.__dict__[kw].__doc__ is not None:20ret.append(kw)21return ret22
23def make_attacker(path):24addition_members = {25"UATAttacker": ["get_triggers"],26}27opt = "===================\nAttackers API\n===================\n\n"28
29opt += "Attacker\n=============\n\n.. autoclass:: OpenAttack.Attacker\n :members:\n\n"30opt += "-" * 36 + "\n\n"31
32opt += "ClassificationAttacker\n==============================\n\n.. autoclass:: OpenAttack.attackers.ClassificationAttacker\n :members:\n\n"33opt += "-" * 36 + "\n\n"34
35
36for name in getSubClasses(OpenAttack.attackers, OpenAttack.ClassificationAttacker):37if name == "ClassificationAttacker":38continue39opt += name + "\n" + ("-" * (2 + len(name))) + "\n\n"40opt += ".. autoclass:: OpenAttack.attackers.%s(OpenAttack.attackers.ClassificationAttacker)\n" % name41
42members = ["__init__"] + (addition_members[name] if name in addition_members else [])43opt += " :members: " + (", ".join(members)) + "\n\n"44open(path, "w", encoding="utf-8").write(opt)45return opt46
47def make_attack_eval(path):48opt = "========================\nAttackEvals API\n========================\n\n"49opt += "AttackEval\n----------------\n\n.. autoclass:: OpenAttack.AttackEval\n :members: __init__, eval, ieval\n\n"50open(path, "w", encoding="utf-8").write(opt)51
52def make_victim(path):53addition_members = {54"TransformersClassifier": ["to"],55}56skip_list = {"Classifier"}57
58opt = "===================\nVictims API\n===================\n\n"59opt += "Classifier\n===========================\n\n.. autoclass:: OpenAttack.victim.classifiers.Classifier\n :members:\n\n"60opt += "-" * 36 + "\n\n"61
62for name in getSubClasses(OpenAttack.victim.classifiers, OpenAttack.victim.classifiers.Classifier):63if name in skip_list:64continue65
66opt += name + "\n" + ("-" * (2 + len(name))) + "\n\n"67opt += ".. autoclass:: OpenAttack.classifiers.%s(OpenAttack.Classifier)\n" % name68
69members = ["__init__"] + (addition_members[name] if name in addition_members else [])70opt += " :members: " + (", ".join(members)) + "\n\n"71open(path, "w", encoding="utf-8").write(opt)72return opt73
74def make_data_manager(path):75opt = "===================\nDataManager API\n===================\n\n.. autoclass:: OpenAttack.DataManager\n :members:"76open(path, "w", encoding="utf-8").write(opt)77return opt78
79def make_data(path):80import pkgutil81cats = {82
83}84for data in pkgutil.iter_modules(OpenAttack.data.__path__):85data = data.module_finder.find_loader(data.name)[0].load_module()86if hasattr(data, "NAME") and (data.NAME in OpenAttack.DataManager.AVAILABLE_DATAS):87name = data.NAME88if name == "test":89continue90cat = name.split(".")91if len(cat) == 1:92continue93name = ".".join(cat[1:])94cat = cat[0]95pack = data.__name__96
97if cat not in cats:98cats[cat] = []99cats[cat].append({100"name": name,101"package": pack102})103
104
105
106for cat in cats.keys():107opt = "=====================\n%s\n=====================\n\n" % cat108opt += ".. _label-data-%s:\n\n" % cat109for data in cats[cat]:110opt += data["name"] + "\n" + ("-" * (2 + len(data["name"]))) + "\n\n"111opt += ".. py:data:: " + cat + "." + data["name"] + "\n\n"112opt += " .. automodule:: OpenAttack.data." + data["package"] + "\n\n"113open(os.path.join(path, cat + ".rst"), "w", encoding="utf-8").write(opt)114return opt115
116def make_metric(path):117opt = "==================\nMetric API\n==================\n\n"118
119
120metrics = []121selector = []122for name in dir(OpenAttack.metric):123if isinstance(OpenAttack.metric.__dict__[name], type):124if issubclass(OpenAttack.metric.__dict__[name], OpenAttack.metric.AttackMetric):125if name == "AttackMetric":126continue127metrics.append(name)128elif issubclass(OpenAttack.metric.__dict__[name], OpenAttack.metric.MetricSelector):129if name == "MetricSelector":130continue131selector.append(name)132
133opt += """Attacker Metrics134==================
135
136.. autoclass:: OpenAttack.metric.AttackMetric
137:members:
138
139
140"""
141
142for name in metrics:143cls = OpenAttack.metric.__dict__[name]144opt += name + "\n" + ("-" * (2 + len(name))) + "\n\n"145opt += ".. autoclass:: OpenAttack.metric." + name + "\n"146if hasattr(cls, "calc_score"):147opt += " :members: __init__, calc_score" + "\n"148else:149opt += " :members: __init__" + "\n"150opt += " :exclude-members: TAGS" + "\n\n"151
152opt += """Metrics Selector153=======================
154
155.. autoclass:: OpenAttack.metric.MetricSelector
156:members:
157
158
159"""
160
161for name in selector:162opt += name + "\n" + ("-" * (2 + len(name))) + "\n\n"163opt += ".. autoclass:: OpenAttack.metric." + name + "\n"164opt += " :members: " + "\n"165opt += " :exclude-members: TAGS" + "\n\n"166
167open(path, "w", encoding="utf-8").write(opt)168return opt169
170def make_substitute(path):171opt = "======================\nSubstitutes API\n======================\n\n"172opt += """173
174Abstract Classes
175------------------------
176
177.. autoclass:: OpenAttack.attack_assist.substitute.word.WordSubstitute
178:members: __call__
179
180.. autoclass:: OpenAttack.attack_assist.substitute.char.CharSubstitute
181:members: __call__
182
183-------------------------------------------------------------------------------
184
185
186"""
187subs = getSubClasses(OpenAttack.attack_assist.substitute.word, OpenAttack.attack_assist.substitute.word.WordSubstitute)188embed_based_idx = subs.index("EmbedBasedSubstitute")189if embed_based_idx != -1:190subs[0], subs[embed_based_idx] = subs[embed_based_idx], subs[0]191
192for name in subs:193cls = OpenAttack.attack_assist.substitute.word.__dict__[name]194if cls is OpenAttack.attack_assist.substitute.word.WordSubstitute:195continue196
197opt += name + "\n" + ("-" * (2 + len(name))) + "\n\n"198opt += ".. autoclass:: OpenAttack.attack_assist.substitute.word.%s(OpenAttack.attack_assist.substitute.word.WordSubstitute)\n" % name199opt += " :members: __init__\n\n"200
201subs = getSubClasses(OpenAttack.attack_assist.substitute.char, OpenAttack.attack_assist.substitute.char.CharSubstitute)202
203for name in subs:204cls = OpenAttack.attack_assist.substitute.char.__dict__[name]205if cls is OpenAttack.attack_assist.substitute.char.CharSubstitute:206continue207
208opt += name + "\n" + ("-" * (2 + len(name))) + "\n\n"209opt += ".. autoclass:: OpenAttack.attack_assist.substitute.char.%s(OpenAttack.attack_assist.substitute.char.CharSubstitute)\n" % name210opt += " :members: __init__\n\n"211
212open(path, "w", encoding="utf-8").write(opt)213return opt214
215def make_text_processor(path):216opt = "========================\nText Processors API\n========================\n\n"217opt += "Tokenizers\n============================\n\n"218opt += """219.. autoclass:: OpenAttack.text_process.tokenizer.Tokenizer
220:members: tokenize, detokenize
221
222"""
223
224import OpenAttack.text_process.tokenizer225
226for name in getSubClasses(OpenAttack.text_process.tokenizer, OpenAttack.text_process.tokenizer.Tokenizer):227if name == "Tokenizer":228continue229opt += name + "\n" + ("-" * (2 + len(name))) + "\n\n"230opt += ".. autoclass:: OpenAttack.text_process.tokenizer.%s(OpenAttack.text_process.tokenizer.Tokenizer)\n" % name231opt += " :members:\n\n"232
233
234import OpenAttack.text_process.lemmatizer235
236opt += "Lemmatizer\n============================\n\n"237opt += """238.. autoclass:: OpenAttack.text_process.lemmatizer.Lemmatizer
239:members: lemmatize, delemmatize
240
241"""
242for name in getSubClasses(OpenAttack.text_process.lemmatizer, OpenAttack.text_process.lemmatizer.Lemmatizer):243if name == "Lemmatizer":244continue245opt += name + "\n" + ("-" * (2 + len(name))) + "\n\n"246opt += ".. autoclass:: OpenAttack.text_process.lemmatizer.%s(OpenAttack.text_process.lemmatizer.Lemmatizer)\n" % name247opt += " :members:\n\n"248
249
250import OpenAttack.text_process.constituency_parser251
252opt += "ConstituencyParser\n============================\n\n"253opt += """254.. autoclass:: OpenAttack.text_process.constituency_parser.ConstituencyParser
255:members: __call__
256
257"""
258for name in getSubClasses(OpenAttack.text_process.constituency_parser, OpenAttack.text_process.constituency_parser.ConstituencyParser):259if name == "ConstituencyParser":260continue261opt += name + "\n" + ("-" * (2 + len(name))) + "\n\n"262opt += ".. autoclass:: OpenAttack.text_process.constituency_parser.%s(OpenAttack.text_process.constituency_parser.ConstituencyParser)\n" % name263opt += " :members:\n\n"264
265
266open(path, "w", encoding="utf-8").write(opt)267return opt268
269def make_utils(path):270opt = "=====================\nutils API\n=====================\n\n"271for name in OpenAttack.utils.__dir__():272if name.startswith("__"):273continue274obj = OpenAttack.utils.__dict__[name]275if type(obj).__name__ == "module":276continue277opt += name + "\n" + ("-" * (2 + len(name))) + "\n\n"278if type(obj).__name__ == "function":279opt += ".. autofunction:: OpenAttack.utils." + name + "\n\n"280else:281opt += ".. autoclass:: OpenAttack.utils." + name + "\n"282opt += " :members: " + "\n\n"283open(path, "w", encoding="utf-8").write(opt)284return opt285
286def main(path):287make_attacker(os.path.join(path, "attacker.rst"))288make_attack_eval(os.path.join(path, "attack_eval.rst"))289make_victim(os.path.join(path, "victim.rst"))290make_data_manager(os.path.join(path, "data_manager.rst"))291make_data(os.path.join(path, "..", "data"))292make_metric(os.path.join(path, "metric.rst"))293make_substitute(os.path.join(path, "substitute.rst"))294make_text_processor(os.path.join(path, "text_processor.rst"))295make_utils(os.path.join(path, "utils.rst"))296
297if __name__ == "__main__":298import sys299path = os.path.abspath(sys.argv[1])300main(path)