1 """Miscellaneous utility functions.
2
3 A load of common utilities used in various places in the codebase
4 and not specific to any formalism, tagger, etc.
5
6 """
7 """
8 ============================== License ========================================
9 Copyright (C) 2008, 2010-12 University of Edinburgh, Mark Granroth-Wilding
10
11 This file is part of The Jazz Parser.
12
13 The Jazz Parser is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 The Jazz Parser is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with The Jazz Parser. If not, see <http://www.gnu.org/licenses/>.
25
26 ============================ End license ======================================
27
28 """
29 __author__ = "Mark Granroth-Wilding <mark.granroth-wilding@ed.ac.uk>"
30
31 from .latex import filter_latex
32 import sys, traceback
33
35 """
36 Given path to a file or directory, checks that the directory (or that
37 containing the file) exists and creates it if not. This is useful to put
38 in before you try creating or outputing to a file.
39
40 @type is_dir: bool
41 @param is_dir: in general, we assume the input name is a file and we
42 want to check its directory. Set is_dir=True if the input is in fact
43 a directory
44
45 @return: True if the directory was created, False if it already existed.
46
47 """
48 import os.path
49 from os import makedirs
50 filename = os.path.abspath(filename)
51
52 if is_dir:
53 dirname = filename
54 else:
55 dirname = os.path.dirname(filename)
56
57 if os.path.exists(dirname):
58 return False
59 else:
60 makedirs(dirname)
61 return True
62
63 -def group_pairs(inlist, none_final=False, none_initial=False):
64 inlist = iter(inlist)
65 last = inlist.next()
66 if none_initial:
67 yield (None, last)
68 for el in inlist:
69 yield (last, el)
70 last = el
71 if none_final:
72 yield (last, None)
73
75 """
76 Returns a tuple containing information about the currently raised
77 exception. This is (type,value,traceback).
78
79 @type str_tb: bool
80 @param str_tb: format the traceback as a string instead of returning
81 it as an object. You'll need to do this if you want to pickle the
82 result.
83
84 """
85 typ = sys.exc_type
86 val = sys.exc_value
87 if str_tb:
88 tb = "".join(traceback.format_exception(typ, val, sys.exc_traceback))
89 else:
90 tb = sys.exc_traceback
91 return (typ, val, tb)
92
94 """
95 Given the full python path to a class, imports the class
96 dynamically and returns it.
97 """
98
99 module_name,__,model_name = full_name.rpartition(".")
100
101 module = __import__(module_name, globals(), locals(), [model_name])
102
103 return getattr(module,model_name)
104
106 """
107 Given the full python path to a package, imports it if possible.
108 If the import fails, raises an OptionalImportError.
109 This is designed for loading packages that come from optional
110 dependencies, so that a sensible error message can uniformly be
111 displayed.
112
113 Only works with absolute paths, because relative paths would be
114 relative to this function's module. Relative paths are explicitly
115 disabled.
116
117 @param dependency_name: a readable name for the package being loaded.
118 @type dependency_name: string
119 @param task: a string identifying the task you're loading it for. This
120 is for readable error output.
121 @type task: string
122
123 """
124 try:
125 module = __import__(full_name, globals(), locals(), level=0)
126 except ImportError:
127 error = "could not load the module %s." % full_name
128 if dependency_name is not None:
129 error += " You seem not to have the optional dependency %s "\
130 "installed." % dependency_name
131 else:
132 error += " This is an optional dependency which you don't "\
133 "have installed."
134 if task is not None:
135 error += " This package is required for %s" % task
136 raise OptionalImportError, error
137 return module
138
140 """
141 Works in the same way as load_optional_package, but corresponds to
142 doing a C{from X import Y}. Note that X and Y do not correspond
143 directly to package_name and object_name, though. Part of X may
144 be found in object_name: this is so that the import of the optional
145 package can be tested before we try loading anything from it, which
146 may generate unrelated import errors, even if the optional
147 package is installed correctly.
148
149 E.g. instead of doing::
150 from nltk.model.ngram import NgramModel
151 we would do::
152 load_from_optional_package('nltk', 'model.ngram.NgramModel')
153 so that we can distinguish between errors loading 'nltk' due to its
154 not being installed and errors importing 'nltk.model.ngram.NgramModel'
155 due to bugs in the module, incorrect class name, etc.
156
157 @param package_name: Python path to the optional package root
158 @param object_name: remainder of the Python path to the object to be
159 returned.
160 """
161
162
163 load_optional_package(package_name, dependency_name=dependency_name, task=task)
164
165 from_module = package_name
166 middle_bit,__,obj_name = object_name.rpartition(".")
167 if middle_bit != "":
168 from_module += ".%s" % middle_bit
169
170 module = __import__(from_module, globals(), locals(), [obj_name], level=0)
171
172 return getattr(module, obj_name)
173
175 """
176 Decorator to make a method abstract. Just raises a
177 NotImplementedError when the method is called.
178
179 """
180 def _get_abstract():
181 def _abstract(*args, **kwargs):
182
183 message = "Tried to call abstract method %s" % fn.__name__
184 if cls is not None:
185 message += " on instance of %s" % cls.__name__
186 raise NotImplementedError, message
187 return _abstract
188 return _get_abstract()
189
191 """
192 Very simple class to wrap up a common method for measuring the
193 execution time of some code. A timer is started when the object
194 is created. Then call get_time() to find out how long its been
195 running in miliseconds.
196
197 By default, this will use C{time.time()} and will therefore measure
198 wall time between starting the timer and ending. You can specify
199 C{clock=True} to report CPU clock time used by the process, using
200 C{time.clock()}. This will make a difference on Unix, but not on
201 Windows, where C{time.clock()} just returns wall time.
202
203 """
205 import time
206 self.clock = clock
207 if clock:
208 self.start_time = time.clock()
209 else:
210 self.start_time = time.time()
211
213 import time
214 if self.clock:
215 return time.clock() - self.start_time
216 else:
217 return time.time() - self.start_time
218
221