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.
12 sys
.stdout
= sys
.stderr
23 # .pyc file (and 'PYC ' resource magic number)
24 MAGIC
= imp
.get_magic()
26 # Template file (searched on sys.path)
27 TEMPLATE
= "PythonApplet"
29 # Specification of our resource
33 # A resource with this name sets the "owner" (creator) of the destination
34 # XXXX Should look for id=0
35 OWNERNAME
= "owner resource"
37 # OpenResFile mode parameters
42 """Locate the applet template along sys.path"""
44 template
= os
.path
.join(p
, TEMPLATE
)
46 template
, d1
, d2
= macfs
.ResolveAliasFile(template
)
48 except (macfs
.error
, ValueError):
51 die("Template %s not found on sys.path" % `TEMPLATE`
)
53 template
= template
.as_pathname()
61 # (there's no point in proceeding if we can't find it)
63 template
= findtemplate()
65 print 'Using template', template
67 # Ask for source text if not specified in sys.argv[1:]
70 srcfss
, ok
= macfs
.PromptGetFile('Select Python source file:', 'TEXT')
73 filename
= srcfss
.as_pathname()
74 tp
, tf
= os
.path
.split(filename
)
79 dstfss
, ok
= macfs
.StandardPutFile('Save application as:', tf
)
81 process(template
, filename
, dstfss
.as_pathname())
84 # Loop over all files to be processed
85 for filename
in sys
.argv
[1:]:
86 process(template
, filename
, '')
88 def process(template
, filename
, output
):
91 print "Processing", `filename`
, "..."
93 # Read the source and compile it
94 # (there's no point overwriting the destination if it has a syntax error)
100 code
= compile(text
, filename
, "exec")
101 except (SyntaxError, EOFError):
102 die("Syntax error in script %s" % `filename`
)
105 # Set the destination file name
107 if string
.lower(filename
[-3:]) == ".py":
108 destname
= filename
[:-3]
109 rsrcname
= destname
+ '.rsrc'
111 destname
= filename
+ ".applet"
112 rsrcname
= filename
+ '.rsrc'
117 # Try removing the output file
124 # Create FSSpecs for the various files
126 template_fss
= macfs
.FSSpec(template
)
127 template_fss
, d1
, d2
= macfs
.ResolveAliasFile(template_fss
)
128 dest_fss
= macfs
.FSSpec(destname
)
130 # Copy data (not resources, yet) from the template
132 tmpl
= open(template
, "rb")
133 dest
= open(destname
, "wb")
140 # Open the output resource fork
143 output
= FSpOpenResFile(dest_fss
, WRITE
)
146 print "Creating resource fork..."
147 CreateResFile(destname
)
148 output
= FSpOpenResFile(dest_fss
, WRITE
)
150 # Copy the resources from the target specific resource template, if any
151 typesfound
, ownertype
= [], None
153 input = FSpOpenResFile(rsrcname
, READ
)
154 except (MacOS
.Error
, ValueError):
157 typesfound
, ownertype
= copyres(input, output
, [], 0)
160 # Check which resource-types we should not copy from the template
162 if 'SIZE' in typesfound
: skiptypes
.append('SIZE')
163 if 'BNDL' in typesfound
: skiptypes
= skiptypes
+ ['BNDL', 'FREF', 'icl4',
164 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
165 skipowner
= (ownertype
<> None)
167 # Copy the resources from the template
169 input = FSpOpenResFile(template_fss
, READ
)
170 dummy
, tmplowner
= copyres(input, output
, skiptypes
, skipowner
)
171 if ownertype
== None:
172 ownertype
= tmplowner
174 if ownertype
== None:
175 die("No owner resource found in either resource file or template")
177 # Now set the creator, type and bundle bit of the destination
178 dest_finfo
= dest_fss
.GetFInfo()
179 dest_finfo
.Creator
= ownertype
180 dest_finfo
.Type
= 'APPL'
181 dest_finfo
.Flags
= dest_finfo
.Flags | MACFS
.kHasBundle
182 dest_finfo
.Flags
= dest_finfo
.Flags
& ~MACFS
.kHasBeenInited
183 dest_fss
.SetFInfo(dest_finfo
)
185 # Make sure we're manipulating the output resource file now
189 # Delete any existing 'PYC ' resource named __main__
192 res
= Get1NamedResource(RESTYPE
, RESNAME
)
197 # Create the raw data for the resource from the code object
199 data
= marshal
.dumps(code
)
201 data
= (MAGIC
+ '\0\0\0\0') + data
203 # Create the resource and write it
207 id = Unique1ID(RESTYPE
)
209 res
.AddResource(RESTYPE
, id, RESNAME
)
211 res
.ReleaseResource()
213 # Close the output file
217 # Give positive feedback
219 message("Applet %s created." % `destname`
)
222 # Copy resources between two resource file descriptors.
223 # skip a resource named '__main__' or (if skipowner is set) 'Owner resource'.
224 # Also skip resources with a type listed in skiptypes.
226 def copyres(input, output
, skiptypes
, skipowner
):
230 ntypes
= Count1Types()
231 for itype
in range(1, 1+ntypes
):
232 type = Get1IndType(itype
)
233 if type in skiptypes
:
235 alltypes
.append(type)
236 nresources
= Count1Resources(type)
237 for ires
in range(1, 1+nresources
):
238 res
= Get1IndResource(type, ires
)
239 id, type, name
= res
.GetResInfo()
240 lcname
= string
.lower(name
)
241 if (type, lcname
) == (RESTYPE
, RESNAME
):
242 continue # Don't copy __main__ from template
243 # XXXX should look for id=0
244 if lcname
== OWNERNAME
:
246 continue # Skip this one
250 attrs
= res
.GetResAttrs()
252 print id, type, name
, size
, hex(attrs
)
257 res2
= Get1Resource(type, id)
262 print "Overwriting..."
263 res2
.RemoveResource()
264 res
.AddResource(type, id, name
)
266 attrs
= attrs | res
.GetResAttrs()
268 print "New attrs =", hex(attrs
)
269 res
.SetResAttrs(attrs
)
271 return alltypes
, ctor
274 # Show a message and exit
283 def message(str, id = 256):
285 d
= GetNewDialog(id, -1)
287 print "Error:", `
str`
288 print "DLOG id =", id, "not found."
290 tp
, h
, rect
= d
.GetDialogItem(2)
291 SetDialogItemText(h
, str)
292 d
.SetDialogDefaultItem(1)
294 n
= ModalDialog(None)
299 if __name__
== '__main__':