Fix three PyChecker-detected gotchas.
[python/dscho.git] / Mac / mkapplet.py
blob99486d4878fa957c8b3f18e489c9a3a3a1940e24
1 """Create an applet from a Python script.
3 This puts up a dialog asking for a Python source file ('TEXT').
4 The output is a file with the same name but its ".py" suffix dropped.
5 It is created by copying an applet template and then adding a 'PYC '
6 resource named __main__ containing the compiled, marshalled script.
7 """
9 import sys
10 sys.stdout = sys.stderr
12 import string
13 import os
14 import marshal
15 import imp
16 import macfs
17 import MacOS
18 from Res import *
20 # .pyc file (and 'PYC ' resource magic number)
21 MAGIC = imp.get_magic()
23 # Template file (searched on sys.path)
24 TEMPLATE = "PythonApplet"
26 # Specification of our resource
27 RESTYPE = 'PYC '
28 RESNAME = '__main__'
30 # A resource with this name sets the "owner" (creator) of the destination
31 OWNERNAME = "owner resource"
33 # OpenResFile mode parameters
34 READ = 1
35 WRITE = 2
37 def main():
39 # Find the template
40 # (there's no point in proceeding if we can't find it)
42 for p in sys.path:
43 template = os.path.join(p, TEMPLATE)
44 try:
45 tmpl = open(template, "rb")
46 tmpl.close()
47 break
48 except IOError:
49 continue
50 else:
51 die("Template %s not found" % `template`)
52 return
54 # Ask for source text if not specified in sys.argv[1:]
56 if not sys.argv[1:]:
57 srcfss, ok = macfs.StandardGetFile('TEXT')
58 if not ok:
59 return
60 filename = srcfss.as_pathname()
61 tp, tf = os.path.split(filename)
62 if tf[-3:] == '.py':
63 tf = tf[:-3]
64 else:
65 tf = tf + '.applet'
66 dstfss, ok = macfs.StandardPutFile('Save application as:', tf)
67 if not ok: return
68 process(template, filename, dstfss.as_pathname())
69 else:
71 # Loop over all files to be processed
72 for filename in sys.argv[1:]:
73 process(template, filename, '')
75 undefs = ('????', ' ', '\0\0\0\0', 'BINA')
77 def process(template, filename, output):
79 print "Processing", `filename`, "..."
81 # Read the source and compile it
82 # (there's no point overwriting the destination if it has a syntax error)
84 fp = open(filename)
85 text = fp.read()
86 fp.close()
87 try:
88 code = compile(text, filename, "exec")
89 except (SyntaxError, EOFError):
90 die("Syntax error in script %s" % `filename`)
91 return
93 # Set the destination file name
95 if string.lower(filename[-3:]) == ".py":
96 destname = filename[:-3]
97 rsrcname = destname + '.rsrc'
98 else:
99 destname = filename + ".applet"
100 rsrcname = filename + '.rsrc'
102 if output:
103 destname = output
104 # Copy the data from the template (creating the file as well)
106 tmpl = open(template, "rb")
107 dest = open(destname, "wb")
108 data = tmpl.read()
109 if data:
110 dest.write(data)
111 dest.close()
112 tmpl.close()
114 # Copy the creator of the template to the destination
115 # unless it already got one. Set type to APPL
117 tctor, ttype = MacOS.GetCreatorAndType(template)
118 ctor, type = MacOS.GetCreatorAndType(destname)
119 if type in undefs: type = 'APPL'
120 if ctor in undefs: ctor = tctor
122 # Open the output resource fork
124 try:
125 output = FSpOpenResFile(destname, WRITE)
126 except MacOS.Error:
127 print "Creating resource fork..."
128 CreateResFile(destname)
129 output = FSpOpenResFile(destname, WRITE)
131 # Copy the resources from the template
133 input = FSpOpenResFile(template, READ)
134 newctor = copyres(input, output)
135 CloseResFile(input)
136 if newctor: ctor = newctor
138 # Copy the resources from the target specific resource template, if any
140 try:
141 input = FSpOpenResFile(rsrcname, READ)
142 except MacOS.Error:
143 pass
144 else:
145 newctor = copyres(input, output)
146 CloseResFile(input)
147 if newctor: ctor = newctor
149 # Now set the creator and type of the destination
151 MacOS.SetCreatorAndType(destname, ctor, type)
153 # Make sure we're manipulating the output resource file now
155 UseResFile(output)
157 # Delete any existing 'PYC 'resource named __main__
159 try:
160 res = Get1NamedResource(RESTYPE, RESNAME)
161 res.RmveResource()
162 except Error:
163 pass
165 # Create the raw data for the resource from the code object
167 data = marshal.dumps(code)
168 del code
169 data = (MAGIC + '\0\0\0\0') + data
171 # Create the resource and write it
173 id = 0
174 while id < 128:
175 id = Unique1ID(RESTYPE)
176 res = Resource(data)
177 res.AddResource(RESTYPE, id, RESNAME)
178 res.WriteResource()
179 res.ReleaseResource()
181 # Close the output file
183 CloseResFile(output)
185 # Give positive feedback
187 message("Applet %s created." % `destname`)
190 # Copy resources between two resource file descriptors.
191 # Exception: don't copy a __main__ resource.
192 # If a resource's name is "owner resource", its type is returned
193 # (so the caller can use it to set the destination's creator)
195 def copyres(input, output):
196 ctor = None
197 UseResFile(input)
198 ntypes = Count1Types()
199 for itype in range(1, 1+ntypes):
200 type = Get1IndType(itype)
201 nresources = Count1Resources(type)
202 for ires in range(1, 1+nresources):
203 res = Get1IndResource(type, ires)
204 id, type, name = res.GetResInfo()
205 lcname = string.lower(name)
206 if (type, lcname) == (RESTYPE, RESNAME):
207 continue # Don't copy __main__ from template
208 if lcname == OWNERNAME: ctor = type
209 size = res.SizeResource()
210 attrs = res.GetResAttrs()
211 print id, type, name, size, hex(attrs)
212 res.LoadResource()
213 res.DetachResource()
214 UseResFile(output)
215 try:
216 res2 = Get1Resource(type, id)
217 except MacOS.Error:
218 res2 = None
219 if res2:
220 print "Overwriting..."
221 res2.RmveResource()
222 res.AddResource(type, id, name)
223 res.WriteResource()
224 attrs = attrs | res.GetResAttrs()
225 print "New attrs =", hex(attrs)
226 res.SetResAttrs(attrs)
227 UseResFile(input)
228 return ctor
231 # Show a message and exit
233 def die(str):
234 message(str)
235 sys.exit(1)
238 # Show a message
240 def message(str, id = 256):
241 from Dlg import *
242 d = GetNewDialog(id, -1)
243 if not d:
244 print "Error:", `str`
245 print "DLOG id =", id, "not found."
246 return
247 tp, h, rect = d.GetDItem(2)
248 SetIText(h, str)
249 while 1:
250 n = ModalDialog(None)
251 if n == 1: break
252 del d
255 if __name__ == '__main__':
256 main()