1import sys 2assert sys.version_info[0] == 3, "This program requires Python 3" 3 4import re 5import doctest 6from io import StringIO 7 8import bitarray 9import bitarray.util 10 11 12BASE_URL = "https://github.com/ilanschnell/bitarray" 13 14NEW_IN = { 15 'frozenbitarray': '1.1', 16 'get_default_endian': '1.3', 17 'util.make_endian': '1.3', 18 'bitarray': '2.3: optional `buffer` argument', 19 'bitarray.bytereverse': '2.2.5: optional `start` and `stop` arguments', 20 'bitarray.count': '1.1.0: optional `start` and `stop` arguments', 21 'bitarray.clear': '1.4', 22 'bitarray.find': '2.1', 23 'bitarray.invert': '1.5.3: optional `index` argument', 24 'decodetree': '1.6', 25 'util.urandom': '1.7', 26 'util.pprint': '1.8', 27 'util.serialize': '1.8', 28 'util.deserialize': '1.8', 29 'util.ba2base': '1.9', 30 'util.base2ba': '1.9', 31 'util.parity': '1.9', 32 'util.rindex': '2.3.0: optional `start` and `stop` arguments', 33 'util.vl_encode': '2.2', 34 'util.vl_decode': '2.2', 35} 36 37DOCS = { 38 'rep': ('Bitarray representations', 'represent.rst'), 39 'vlf': ('Variable length bitarray format', 'variable_length.rst'), 40} 41 42DOC_LINKS = { 43 'util.ba2base': 'rep', 44 'util.base2ba': 'rep', 45 'util.serialize': 'rep', 46 'util.deserialize': 'rep', 47 'util.vl_encode': 'vlf', 48 'util.vl_decode': 'vlf', 49} 50 51_NAMES = set() 52 53sig_pat = re.compile(r'(\w+\([^()]*\))( -> (.+))?') 54def write_doc(fo, name): 55 _NAMES.add(name) 56 doc = eval('bitarray.%s.__doc__' % name) 57 assert doc, name 58 lines = doc.splitlines() 59 m = sig_pat.match(lines[0]) 60 if m is None: 61 raise Exception("signature line invalid: %r" % lines[0]) 62 s = '``%s``' % m.group(1) 63 if m.group(3): 64 s += ' -> %s' % m.group(3) 65 fo.write('%s\n' % s) 66 assert lines[1] == '' 67 for line in lines[2:]: 68 out = line.rstrip() 69 fo.write(" %s\n" % out.replace('`', '``') if out else "\n") 70 71 link = DOC_LINKS.get(name) 72 if link: 73 title, filename = DOCS[link] 74 url = BASE_URL + '/blob/master/doc/' + filename 75 fo.write("\n See also: `%s <%s>`__\n" % (title, url)) 76 77 new_in = NEW_IN.get(name) 78 if new_in: 79 fo.write("\n New in version %s.\n" % new_in.replace('`', '``')) 80 81 fo.write('\n\n') 82 83 84def write_reference(fo): 85 fo.write("""\ 86Reference 87========= 88 89bitarray version: %s -- `change log <%s>`__ 90 91In the following, ``item`` and ``value`` are usually a single bit - 92an integer 0 or 1. 93 94 95The bitarray object: 96-------------------- 97 98""" % (bitarray.__version__, BASE_URL + "/blob/master/doc/changelog.rst")) 99 write_doc(fo, 'bitarray') 100 101 fo.write("**A bitarray object supports the following methods:**\n\n") 102 for method in sorted(dir(bitarray.bitarray)): 103 if method.startswith('_'): 104 continue 105 write_doc(fo, 'bitarray.%s' % method) 106 107 fo.write("Other objects:\n" 108 "--------------\n\n") 109 write_doc(fo, 'frozenbitarray') 110 write_doc(fo, 'decodetree') 111 112 fo.write("Functions defined in the `bitarray` module:\n" 113 "-------------------------------------------\n\n") 114 for func in sorted(['test', 'bits2bytes', 'get_default_endian']): 115 write_doc(fo, func) 116 117 fo.write("Functions defined in `bitarray.util` module:\n" 118 "--------------------------------------------\n\n" 119 "This sub-module was add in version 1.2.\n\n") 120 for func in bitarray.util.__all__: 121 write_doc(fo, 'util.%s' % func) 122 123 for name in list(NEW_IN) + list(DOC_LINKS): 124 assert name in _NAMES, name 125 126def update_readme(path): 127 ver_pat = re.compile(r'(bitarray.+?)(\d+\.\d+\.\d+)') 128 129 with open(path, 'r') as fi: 130 data = fi.read() 131 132 with StringIO() as fo: 133 for line in data.splitlines(): 134 if line == 'Reference': 135 break 136 line = ver_pat.sub(lambda m: m.group(1) + bitarray.__version__, 137 line) 138 fo.write("%s\n" % line.rstrip()) 139 140 write_reference(fo) 141 new_data = fo.getvalue() 142 143 if new_data == data: 144 print("already up-to-date") 145 else: 146 with open(path, 'w') as f: 147 f.write(new_data) 148 149 150def write_changelog(fo): 151 ver_pat = re.compile(r'(\d{4}-\d{2}-\d{2})\s+(\d+\.\d+\.\d+)') 152 hash_pat = re.compile(r'#([0-9a-f]+)') 153 link_pat = re.compile(r'\[(.+)\]\((.+)\)') 154 155 def hash_replace(match): 156 group1 = match.group(1) 157 if len(group1) >= 7: 158 if len(group1) != 8: 159 print("Warning: commit hash length != 8, got", len(group1)) 160 url = "%s/commit/%s" % (BASE_URL, group1) 161 else: 162 url = "%s/issues/%d" % (BASE_URL, int(group1)) 163 return "`%s <%s>`__" % (match.group(0), url) 164 165 fo.write("Change log\n" 166 "==========\n\n") 167 168 for line in open('./CHANGE_LOG'): 169 line = line.rstrip() 170 match = ver_pat.match(line) 171 if match: 172 line = match.expand(r'**\2** (\1):') 173 elif line.startswith('-----'): 174 line = '' 175 elif line.startswith(' '): 176 line = line[2:] 177 line = line.replace('`', '``') 178 line = hash_pat.sub(hash_replace, line) 179 line = link_pat.sub( 180 lambda m: "`%s <%s>`__" % (m.group(1), m.group(2)), line) 181 fo.write(line + '\n') 182 183 184def main(): 185 if len(sys.argv) > 1: 186 sys.exit("no arguments expected") 187 188 update_readme('./README.rst') 189 with open('./doc/reference.rst', 'w') as fo: 190 write_reference(fo) 191 with open('./doc/changelog.rst', 'w') as fo: 192 write_changelog(fo) 193 194 doctest.testfile('./README.rst') 195 doctest.testfile('./doc/buffer.rst') 196 doctest.testfile('./doc/represent.rst') 197 doctest.testfile('./doc/variable_length.rst') 198 199 200if __name__ == '__main__': 201 main() 202