root/trunk/dabo/lib/utils.py

Revision 4855, 7.4 kB (checked in by cito, 3 weeks ago)

Since Py 2.4 is now required, sorted() can be used, and sort should use the key and reverse arguments. Not yet changed in list controls.

  • Property svn:eol-style set to native
Line 
1 # -*- coding: utf-8 -*-
2
3 # This serves as a catch-all script for common utilities that may be used
4 # in lots of places throughout Dabo. Typically, to use a function 'foo()' in
5 # this file, add the following import statement to your script:
6 #
7 #   import dabo.lib.utils as utils
8 #
9 # Then, in your code, simply call:
10 #
11 #   utils.foo()
12
13 import os
14 import sys
15 import dabo
16 try:
17     from win32com.shell import shell, shellcon
18 except ImportError:
19     shell, shellcon = None, None
20
21
22 # can't compare NoneType to some types: sort None lower than anything else:
23 def noneSortKey(vv):
24     vv = vv[0]
25     if vv is None:
26         return (0, None)
27     else:
28         return (1, vv)
29
30
31 def caseInsensitiveSortKey(vv):
32     return (vv[0] or "").lower()
33
34
35 def reverseText(tx):
36     """Takes a string and returns it reversed. Example:
37     
38     utils.reverseText("Wow, this is so cool!")
39         => returns "!looc os si siht ,woW"
40     """
41     return tx[::-1]
42
43
44 def getUserHomeDirectory():
45     """Return the user's home directory in a platform-portable way.
46
47     If the home directory cannot be determined, return None.
48     """
49     hd = None
50
51     # If we are on Windows and win32com is available, get the user home
52     # directory using the Windows API:
53     if shell and shellcon:
54         return shell.SHGetFolderPath(0, shellcon.CSIDL_PROFILE, 0, 0)
55
56     # os.path.expanduser should work on all posix systems (*nix, Mac, and some
57     # Windows NT setups):
58     hd = os.path.expanduser("~")
59
60     # If for some reason the posix function above didn't work, most Linux setups
61     # define the environmental variable $HOME, and perhaps this is done sometimes
62     # on Mac and Win as well:
63     if hd is None:
64         hd = os.environ.get("HOME")
65
66     # If we still haven't found a value, Windows tends to define a $USERPROFILE
67     # directory, which usually expands to something like
68     #    c:\Documents and Settings\maryjane
69     if hd is None:
70         hd = os.environ.get("USERPROFILE")
71
72     return hd
73
74
75 def getUserAppDataDirectory(appName="Dabo"):
76     """Return the directory where Dabo can save user preference and setting information.
77
78     On *nix, this will be something like /home/pmcnett/.dabo
79     On Windows, it will be more like c:\Documents and Settings\pmcnett\Application Data\Dabo
80
81     This function relies on platform conventions to determine this information. If it
82     cannot be determined (because platform conventions were circumvented), the return
83     value will be None.
84
85     if appName is passed, the directory will be named accordingly.
86
87     This function will try to create the directory if it doesn't already exist, but if the
88     creation of the directory fails, the return value will revert to None.
89     """
90     dd = None
91
92     if sys.platform not in ("win32",):
93         # On Unix, change appname to lower, don't allow spaces, and prepend a ".":
94         appName = ".%s" % appName.lower().replace(" ", "_")
95
96     # First, on Windows, try the Windows API function:
97     if shell and shellcon:
98         dd = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0)
99    
100     if dd is None and sys.platform == "win32":
101         # We are on Windows, but win32com wasn't installed. Look for the APPDATA
102         # environmental variable:
103         dd = os.environ.get("APPDATA")
104
105     if dd is None:
106         # We are either not on Windows, or we couldn't locate the directory for
107         # whatever reason. Try going off the home directory:
108         dd = getUserHomeDirectory()
109
110     if dd is not None:
111         dd = os.path.join(dd, appName)
112         if not os.path.exists(dd):
113             # try to create the dabo directory:
114             try:
115                 os.makedirs(dd)
116             except OSError:
117                 sys.stderr.write("Couldn't create the user setting directory (%s)." % dd)
118                 dd = None
119     return dd
120    
121    
122 def dictStringify(dct):
123     """The ability to pass a properties dict to an object relies on
124     the practice of passing '**properties' to a function. Seems that
125     Python requires that the keys in any dict being expanded like
126     this be strings, not unicode. This method returns a dict with all
127     unicode keys changed to strings.
128     """
129     ret = {}
130     for kk, vv in dct.items():
131         if isinstance(kk, unicode):
132             try:
133                 ret[str(kk)] = vv
134             except UnicodeEncodeError:
135                 kk = kk.encode(dabo.defaultEncoding)
136                 ret[kk] = vv
137         else:
138             ret[kk] = vv
139     return ret
140        
141
142 def relativePathList(toLoc, fromLoc=None):
143     """Given two paths, returns a list that, when joined with
144     os.path.sep, gives the relative path from 'fromLoc' to
145     "toLoc'. If 'fromLoc' is not specified, the current directory
146     is assumed.
147     """
148     if fromLoc is None:
149         fromLoc = os.getcwd()
150     if toLoc.startswith(".."):
151         if os.path.isdir(fromLoc):
152             toLoc = os.path.join(fromLoc, toLoc)
153         else:
154             toLoc = os.path.join(os.path.split(fromLoc)[0], toLoc)
155     toLoc = os.path.abspath(toLoc)
156     if os.path.isfile(toLoc):
157         toDir, toFile = os.path.split(toLoc)
158     else:
159         toDir = toLoc
160         toFile = ""
161     fromLoc = os.path.abspath(fromLoc)
162     if os.path.isfile(fromLoc):
163         fromLoc = os.path.split(fromLoc)[0]
164     fromList = fromLoc.split(os.path.sep)
165     toList = toDir.split(os.path.sep)
166     # There can be empty strings from the split
167     while len(fromList) > 0 and not fromList[0]:
168         fromList.pop(0)
169     while len(toList) > 0 and not toList[0]:
170         toList.pop(0)
171     lev = 0
172     while (len(fromList) > lev) and (len(toList) > lev) and \
173             (fromList[lev] == toList[lev]):
174         lev += 1
175    
176     # 'lev' now contains the first level where they differ
177     fromDiff = fromList[lev:]
178     toDiff = toList[lev:]
179     ret = [".."] * len(fromDiff) + toDiff
180     if toFile:
181         ret += [toFile]
182     return ret
183
184
185 def relativePath(toLoc, fromLoc=None):
186     """Given two paths, returns a relative path from fromLoc to toLoc."""
187     return os.path.sep.join(relativePathList(toLoc, fromLoc))
188
189
190 def getPathAttributePrefix():
191     return "path://"
192
193
194 def resolveAttributePathing(atts, pth=None):
195     """Dabo design files store their information in XML, which means
196     when they are 'read' the values come back in a dictionary of
197     attributes, which are then used to restore the designed object to its
198     intended state. Path values will be stored in a relative path format,
199     with the value preceeded by the string returned by
200     getPathAttributePrefix(); i.e., 'path://'.
201     
202     This method finds all values that begin with the 'path://' label,
203     strips off that label, converts the paths back to values that
204     can be used by the object, and then updates the attribute dict with
205     those new values.
206     """
207     prfx = getPathAttributePrefix()
208     pathsToConvert = [(kk, vv) for kk, vv in atts.items()
209             if isinstance(vv, basestring) and vv.startswith(prfx)]
210     for convKey, convVal in pathsToConvert:
211         # Strip the path designator
212         convVal = convVal.replace(prfx, "")
213         # Convert to relative path
214         relPath = relativePath(convVal, pth)
215         # Update the atts
216         atts[convKey] = relPath
217
218
219 def resolvePath(val, pth=None, abspath=False):
220     """Takes a single string value in the format Dabo uses to store pathing
221     in XML, and returns the original path relative to the specified path (or the
222     current directory, if no pth is specified). If 'abspath' is True, returns an
223     absolute path instead of the default relative path.
224     """
225     prfx = getPathAttributePrefix()
226     # Strip the path designator
227     val = val.replace(prfx, "")
228     # Convert to relative path
229     ret = relativePath(val, pth)
230     if abspath:
231         ret = os.path.abspath(ret)
232     return ret
233
234
235 def cleanMenuCaption(cap, bad=None):
236     """Menu captions can contain several special characters that make them
237     unsuitable for things such as preference settings. This method provides
238     a simple way of getting the 'clean' version of these captions. By default it
239     strips ampersands, spaces and periods; you can change that by passing
240     the characters you want stripped in the 'bad' parameter.
241     """
242     if bad is None:
243         bad = "&. "
244     ret = cap
245     for ch in bad:
246         ret = ret.replace(ch, "")
247     return ret
Note: See TracBrowser for help on using the browser.