-
Notifications
You must be signed in to change notification settings - Fork 2
/
create_Constructor_Getters_Setters.py
225 lines (197 loc) · 8.96 KB
/
create_Constructor_Getters_Setters.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#
# Date: 8 February 2021
# Description: Creates a Constructor, Setters, and Getters for a
# given list of Class Attributes supplied in the
# input file.
# Input file format has two possible formats.
# <attribute name>
# <attribute name> = <initialisation of the type>
# Examples follow.
# context_name = ""
# num_images = 0
# friends = []
# __id
""" Updated 2021-02-07 to make allowance for hidden attributes, and to include
creation of a Constructor.
Have changed the indent of a tab to the PEP-008 recommended four spaces.
Added the option to distinguish private and protected attributes from
public ones.
In truth, only non-public attributes warrant a getter and a setter.
An option is present to allow creation of getters and setters for
all attributes, or only those that are not public.
Updated 2021-07-11 to add property decorators as a second option.
Both options are printed in the output file.
"""
import sys
def str2bool(stuff):
"""Converts a string to a Boolean as a human would expect."""
return stuff.lower() in ("yes", "true", "y", "1")
def open_files(input_file_name, output_file_name):
"""
Opens both the input and output files,
returning pointers to those files.
"""
# Check that the input file is present and can be opened for reading.
try:
input_file = open(input_file_name, "r")
except IOError as err:
print(f"Cannot find or open the file: {input_file_name}.")
sys.exit()
# Check that we can open the output file for writing,
# creating it first, if necessary.
try:
output_file = open(output_file_name, "w")
except IOError as err:
print(f"Cannot find or open the file: {output_file_name}.")
sys.exit()
return input_file, output_file
def read_input(input_file):
"""
Reads the input file for a list of attributes of the Class,
returning said list.
"""
class_attributes = []
try:
attributes_from_file = input_file.readlines()
except IOError as err:
print(f"Cannot read the list of attributes from the file: \
{output_file_name}.")
sys.exit()
# We shall ignore any lines beginning with a hash ("#") and anything
# following the first space.
for each_line in attributes_from_file:
"""
Create a list of the name and the name cleaned of
any prefixed underscores.
"""
if (len(each_line.strip()) > 0) and (each_line[0] != "#"):
attrib_names = []
attrib_names.append(each_line.strip().split()[0])
attrib_names.append(attrib_names[0].lstrip("_"))
class_attributes.append(attrib_names)
return class_attributes
def create_output(class_attributes, output_file, do_for_all_attributes):
""" Write out the constructor, and those getters and setters required
according to the arguments supplied.
"""
try:
# Added 2021-02-07 to create a Constructor
output_file.write("class Something:\n\n")
output_file.write(" #--------- Constructor --------\n")
output_file.write(" def __init__(self, ")
counter = 0
# output Constructor declaration
for each_var in class_attributes:
counter += 1
if counter == len(class_attributes):
output_file.write(each_var[1] + "):\n\n")
else:
output_file.write(each_var[1] + ", ")
# output initialisation of Attributes
for each_var in class_attributes:
output_file.write(" self." + each_var[0] + " = " + each_var[1] + "\n")
output_file.write("\n\n")
# output Accessors per Attribute
output_file.write(" #----------- Getters ----------\n")
for each_var in class_attributes:
if do_for_all_attributes:
output_file.write(f" def get_{each_var[1]}(self):\n")
output_file.write(f" return self.{each_var[0]}\n\n")
elif (each_var[0] != each_var[1]):
output_file.write(f" def get_{each_var[1]}(self):\n")
output_file.write(f" return self.{each_var[0]}\n\n")
output_file.write("\n\n")
# output Mutators per Attribute
output_file.write(" #----------- Setters ----------\n")
for each_var in class_attributes:
if do_for_all_attributes:
output_file.write(f" def set_{each_var[1]}(self, value):\n")
output_file.write(f" self.{each_var[0]} = value\n\n")
elif (each_var[0] != each_var[1]):
output_file.write(f" def set_{each_var[1]}(self, value):\n")
output_file.write(f" self.{each_var[0]} = value\n\n")
output_file.write("\n\n")
# line to show end of output
output_file.write(("#" + "-" * 30) + "\n\n\n")
except IOError as err:
print(f"Cannot write to the file: {output_file_name}.")
sys.exit()
def create_property_decorator_output(class_attributes, output_file, do_for_all_attributes):
""" Write out the constructor, and those getters and setters required
according to the arguments supplied. Add property decorators as required.
This option only makes sense for non-public attributes.
"""
try:
# Set separator.
output_file.write("\n#" + ("=" * 30) + "\n")
output_file.write("# Use the code above or the code below, depending ")
output_file.write("on whether you want to use property decorators.\n")
output_file.write("#" + ("=" * 30) + "\n\n")
# Added 2021-02-07 to create a Constructor
output_file.write("class Something:\n\n")
output_file.write(" #--------- Constructor --------\n")
output_file.write(" def __init__(self, ")
counter = 0
# output Constructor declaration
for each_var in class_attributes:
counter += 1
if counter == len(class_attributes):
output_file.write(each_var[1] + "):\n\n")
else:
output_file.write(each_var[1] + ", ")
# output initialisation of Attributes
for each_var in class_attributes:
if (each_var[0] != each_var[1]):
output_file.write(" self." + each_var[1] + " = " + each_var[1] )
output_file.write(" # This is not an attribute assignment; it calls the setter.\n")
else:
output_file.write(" self." + each_var[0] + " = " + each_var[1] + "\n")
output_file.write("\n\n")
# output Accessors per Attribute
output_file.write(" #----------- Getters ----------\n")
for each_var in class_attributes:
if (each_var[0] != each_var[1]):
output_file.write(f" @property\n def {each_var[1]}(self):\n")
output_file.write(f" return self.{each_var[0]}\n\n")
output_file.write("\n\n")
# output Mutators per Attribute
output_file.write(" #----------- Setters ----------\n")
for each_var in class_attributes:
if (each_var[0] != each_var[1]):
output_file.write(f" @{each_var[1]}.setter\n def {each_var[1]}(self, value):\n")
output_file.write(f" self.{each_var[0]} = value\n\n")
output_file.write("\n\n")
# line to show end of output
output_file.write(("#" + "-" * 30) + "\n\n\n")
except IOError as err:
print(f"Cannot write to the file: {output_file_name}.")
sys.exit()
def clean_up_and_close(*all_files):
"""Closes all files, whose pointers are sent as arguments."""
try:
for each_file in all_files:
each_file.close()
except IOError as err:
# We do not care, if we cannot close the file.
# Python should manage this for us anyway.
pass
def main():
# Constants
INPUT_FILE_NAME = "input.txt"
OUTPUT_FILE_NAME = "output.txt"
# Getters and Setters for all, or only non-public attributes.
# This might be supplied as a command-line argument instead,
# in a later version.
DO_FOR_ALL_ATTRIBUTES = True
# Process the attribute information and create the code.
input_file, output_file = open_files(INPUT_FILE_NAME, OUTPUT_FILE_NAME)
class_attributes = read_input(input_file)
create_output(class_attributes, output_file, DO_FOR_ALL_ATTRIBUTES)
# Add property decorators as an alternate option.
create_property_decorator_output(class_attributes, output_file, DO_FOR_ALL_ATTRIBUTES)
# Finalise and clean up.
clean_up_and_close(input_file, output_file)
print("\nCreation of Constructor, Accessors, and Mutators complete!")
print("Do change the name of the Class and adjust the output to match your needs!\n")
if __name__ == '__main__':
main()