add_attribute.py
1 #!/usr/bin/env python 2 ############################ Copyrights and license ############################ 3 # # 4 # Copyright 2013 Vincent Jacques <vincent@vincent-jacques.net> # 5 # Copyright 2014 Thialfihar <thi@thialfihar.org> # 6 # Copyright 2014 Vincent Jacques <vincent@vincent-jacques.net> # 7 # Copyright 2016 Peter Buckley <dx-pbuckley@users.noreply.github.com> # 8 # Copyright 2018 Yossarian King <yggy@blackbirdinteractive.com> # 9 # Copyright 2018 sfdye <tsfdye@gmail.com> # 10 # Copyright 2019 Steve Kowalik <steven@wedontsleep.org> # 11 # Copyright 2019 Wan Liuyang <tsfdye@gmail.com> # 12 # Copyright 2020 Isac Souza <isouza@daitan.com> # 13 # Copyright 2020 Steve Kowalik <steven@wedontsleep.org> # 14 # Copyright 2020 Wan Liuyang <tsfdye@gmail.com> # 15 # Copyright 2021 karsten-wagner <39054096+karsten-wagner@users.noreply.github.com># 16 # Copyright 2022 Gabriele Oliaro <ict@gabrieleoliaro.it> # 17 # Copyright 2023 Jonathan Leitschuh <Jonathan.Leitschuh@gmail.com> # 18 # # 19 # This file is part of PyGithub. # 20 # http://pygithub.readthedocs.io/ # 21 # # 22 # PyGithub is free software: you can redistribute it and/or modify it under # 23 # the terms of the GNU Lesser General Public License as published by the Free # 24 # Software Foundation, either version 3 of the License, or (at your option) # 25 # any later version. # 26 # # 27 # PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY # 28 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # 29 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # 30 # details. # 31 # # 32 # You should have received a copy of the GNU Lesser General Public License # 33 # along with PyGithub. If not, see <http://www.gnu.org/licenses/>. # 34 # # 35 ################################################################################ 36 from __future__ import annotations 37 38 import os.path 39 import sys 40 41 className, attributeName, attributeType = sys.argv[1:4] 42 if len(sys.argv) > 4: 43 attributeClassType = sys.argv[4] 44 else: 45 attributeClassType = "" 46 47 types = { 48 "string": ( 49 "str", 50 None, 51 'self._makeStringAttribute(attributes["' + attributeName + '"])', 52 "str", 53 ), 54 "int": ( 55 "int", 56 None, 57 'self._makeIntAttribute(attributes["' + attributeName + '"])', 58 "int", 59 ), 60 "bool": ( 61 "bool", 62 None, 63 'self._makeBoolAttribute(attributes["' + attributeName + '"])', 64 "bool", 65 ), 66 "datetime": ( 67 "datetime", 68 "str", 69 'self._makeDatetimeAttribute(attributes["' + attributeName + '"])', 70 "datetime", 71 ), 72 "class": ( 73 ":class:`" + attributeClassType + "`", 74 None, 75 "self._makeClassAttribute(" + attributeClassType + ', attributes["' + attributeName + '"])', 76 attributeClassType, 77 ), 78 } 79 80 attributeDocType, attributeAssertType, attributeValue, attributeClassType = types[attributeType] 81 if attributeType == "class": 82 # Wrap in quotes to avoid an explicit import requirement which can cause circular import errors 83 attributeClassType = f"'{attributeClassType}'" 84 85 fileName = os.path.join("github", className + ".py") 86 87 88 def add_as_class_property(lines: list[str]) -> list[str]: 89 newLines = [] 90 i = 0 91 92 added = False 93 94 isCompletable = True 95 isProperty = False 96 while not added: 97 line = lines[i].rstrip() 98 i += 1 99 if line.startswith("class "): 100 if "NonCompletableGithubObject" in line: 101 isCompletable = False 102 elif line == " @property": 103 isProperty = True 104 elif line.startswith(" def "): 105 attrName = line[8:-7] 106 # Properties will be inserted after __repr__, but before any other function. 107 if (not attrName.startswith("__repr__") and not attrName.startswith("_initAttributes")) and ( 108 attrName == "_identity" or attrName > attributeName or not isProperty 109 ): 110 if not isProperty: 111 newLines.append(" @property") 112 newLines.append(" def " + attributeName + "(self) -> " + attributeClassType + ":") 113 if isCompletable: 114 newLines.append(" self._completeIfNotSet(self._" + attributeName + ")") 115 newLines.append(" return self._" + attributeName + ".value") 116 newLines.append("") 117 if isProperty: 118 newLines.append(" @property") 119 added = True 120 isProperty = False 121 newLines.append(line) 122 123 while i < len(lines): 124 line = lines[i].rstrip() 125 i += 1 126 newLines.append(line) 127 128 return newLines 129 130 131 def add_to_initAttributes(lines: list[str]) -> list[str]: 132 newLines = [] 133 added = False 134 135 i = 0 136 inInit = False 137 138 while not added: 139 line = lines[i].rstrip() 140 i += 1 141 if line.strip().startswith("def _initAttributes(self)"): 142 inInit = True 143 if inInit: 144 if not line or line.endswith(" = github.GithubObject.NotSet") or line.endswith(" = NotSet"): 145 if line: 146 attrName = line[14:-29] 147 if not line or attrName > attributeName: 148 newLines.append(f" self._{attributeName}: Attribute[{attributeClassType}] = NotSet") 149 added = True 150 newLines.append(line) 151 152 while i < len(lines): 153 line = lines[i].rstrip() 154 i += 1 155 newLines.append(line) 156 157 return newLines 158 159 160 def add_to_useAttributes(lines: list[str]) -> list[str]: 161 i = 0 162 newLines = [] 163 added = False 164 inUse = False 165 while not added: 166 try: 167 line = lines[i].rstrip() 168 except IndexError: 169 line = "" 170 i += 1 171 if line.strip().startswith("def _useAttributes(self, attributes:"): 172 inUse = True 173 if inUse: 174 if not line or line.endswith(" in attributes: # pragma no branch"): 175 if line: 176 attrName = line[12:-36] 177 if not line or attrName > attributeName: 178 newLines.append(' if "' + attributeName + '" in attributes: # pragma no branch') 179 if attributeAssertType: 180 newLines.append( 181 ' assert attributes["' 182 + attributeName 183 + '"] is None or isinstance(attributes["' 184 + attributeName 185 + '"], ' 186 + attributeAssertType 187 + '), attributes["' 188 + attributeName 189 + '"]' 190 ) 191 newLines.append(f" self._{attributeName} = {attributeValue}") 192 added = True 193 newLines.append(line) 194 195 while i < len(lines): 196 line = lines[i].rstrip() 197 i += 1 198 newLines.append(line) 199 200 return newLines 201 202 203 with open(fileName) as f: 204 source = f.readlines() 205 206 source = add_as_class_property(source) 207 source = add_to_initAttributes(source) 208 source = add_to_useAttributes(source) 209 210 with open(fileName, "w", newline="\n") as f: 211 f.write("\n".join(source) + "\n")