| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
import datetime |
|---|
| 22 |
import logging |
|---|
| 23 |
import logging.config |
|---|
| 24 |
import os |
|---|
| 25 |
import sys |
|---|
| 26 |
import time |
|---|
| 27 |
import traceback |
|---|
| 28 |
import types |
|---|
| 29 |
|
|---|
| 30 |
from GeoEco.DynamicDocString import DynamicDocString |
|---|
| 31 |
from GeoEco.Internationalization import _, UnicodeToUserPreferredEncoding, UserPreferredEncodingToUnicode |
|---|
| 32 |
|
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 |
|
|---|
| 36 |
class Logger(object): |
|---|
| 37 |
__doc__ = DynamicDocString() |
|---|
| 38 |
|
|---|
| 39 |
_LogInfoAsDebug = False |
|---|
| 40 |
_LogErrorsAsWarnings = False |
|---|
| 41 |
|
|---|
| 42 |
@classmethod |
|---|
| 43 |
def GetLogInfoAsDebug(cls): |
|---|
| 44 |
return Logger._LogInfoAsDebug |
|---|
| 45 |
|
|---|
| 46 |
@classmethod |
|---|
| 47 |
def SetLogInfoAsDebug(cls, value): |
|---|
| 48 |
if not isinstance(value, types.BooleanType): |
|---|
| 49 |
RaiseException(TypeError(_(u'The value provided for the value parameter is an invalid type ("%(badType)s" in Python). Please provide a value having the Python type "bool".') % {u'badType' : type(value).__name__})) |
|---|
| 50 |
Logger._LogInfoAsDebug = value |
|---|
| 51 |
|
|---|
| 52 |
LogInfoAsDebug = property(GetLogInfoAsDebug, SetLogInfoAsDebug, doc=DynamicDocString()) |
|---|
| 53 |
|
|---|
| 54 |
@classmethod |
|---|
| 55 |
def GetLogErrorsAsWarnings(cls): |
|---|
| 56 |
return Logger._LogErrorsAsWarnings |
|---|
| 57 |
|
|---|
| 58 |
@classmethod |
|---|
| 59 |
def SetLogErrorsAsWarnings(cls, value): |
|---|
| 60 |
if not isinstance(value, types.BooleanType): |
|---|
| 61 |
RaiseException(TypeError(_(u'The value provided for the value parameter is an invalid type ("%(badType)s" in Python). Please provide a value having the Python type "bool".') % {u'badType' : type(value).__name__})) |
|---|
| 62 |
Logger._LogErrorsAsWarnings = value |
|---|
| 63 |
|
|---|
| 64 |
LogErrorsAsWarnings = property(GetLogErrorsAsWarnings, SetLogErrorsAsWarnings, doc=DynamicDocString()) |
|---|
| 65 |
|
|---|
| 66 |
@classmethod |
|---|
| 67 |
def Debug(cls, format, *args): |
|---|
| 68 |
try: |
|---|
| 69 |
logging.getLogger(u'GeoEco').debug(format.rstrip(), *args) |
|---|
| 70 |
except: |
|---|
| 71 |
pass |
|---|
| 72 |
|
|---|
| 73 |
@classmethod |
|---|
| 74 |
def Info(cls, format, *args): |
|---|
| 75 |
try: |
|---|
| 76 |
if cls.GetLogInfoAsDebug(): |
|---|
| 77 |
logging.getLogger(u'GeoEco').debug(format.rstrip(), *args) |
|---|
| 78 |
else: |
|---|
| 79 |
logging.getLogger(u'GeoEco').info(format.rstrip(), *args) |
|---|
| 80 |
except: |
|---|
| 81 |
pass |
|---|
| 82 |
|
|---|
| 83 |
@classmethod |
|---|
| 84 |
def Warning(cls, format, *args): |
|---|
| 85 |
try: |
|---|
| 86 |
logging.getLogger(u'GeoEco').warning(format.rstrip(), *args) |
|---|
| 87 |
except: |
|---|
| 88 |
pass |
|---|
| 89 |
|
|---|
| 90 |
@classmethod |
|---|
| 91 |
def Error(cls, format, *args): |
|---|
| 92 |
try: |
|---|
| 93 |
if cls.GetLogErrorsAsWarnings(): |
|---|
| 94 |
logging.getLogger(u'GeoEco').warning(format.rstrip(), *args) |
|---|
| 95 |
else: |
|---|
| 96 |
logging.getLogger(u'GeoEco').error(format.rstrip(), *args) |
|---|
| 97 |
except: |
|---|
| 98 |
pass |
|---|
| 99 |
|
|---|
| 100 |
@classmethod |
|---|
| 101 |
def RaiseException(cls, exception): |
|---|
| 102 |
try: |
|---|
| 103 |
raise exception |
|---|
| 104 |
except: |
|---|
| 105 |
if cls.GetLogErrorsAsWarnings(): |
|---|
| 106 |
cls.LogExceptionAsWarning() |
|---|
| 107 |
else: |
|---|
| 108 |
cls.LogExceptionAsError() |
|---|
| 109 |
raise |
|---|
| 110 |
|
|---|
| 111 |
@classmethod |
|---|
| 112 |
def LogInfoAndSetInfoToDebug(cls, format, *args): |
|---|
| 113 |
cls.Info(format, *args) |
|---|
| 114 |
oldValue = cls.GetLogInfoAsDebug() |
|---|
| 115 |
cls.SetLogInfoAsDebug(True) |
|---|
| 116 |
return oldValue |
|---|
| 117 |
|
|---|
| 118 |
@classmethod |
|---|
| 119 |
def LogExceptionAsWarning(cls, format=None, *args): |
|---|
| 120 |
cls._LogExceptionAndMessage(logging.WARNING, format, *args) |
|---|
| 121 |
|
|---|
| 122 |
@classmethod |
|---|
| 123 |
def LogExceptionAsError(cls, format=None, *args): |
|---|
| 124 |
if cls.GetLogErrorsAsWarnings(): |
|---|
| 125 |
cls._LogExceptionAndMessage(logging.WARNING, format, *args) |
|---|
| 126 |
else: |
|---|
| 127 |
cls._LogExceptionAndMessage(logging.ERROR, format, *args) |
|---|
| 128 |
|
|---|
| 129 |
_ExceptionTracebackID = None |
|---|
| 130 |
_ReportedSubsequentErrors = False |
|---|
| 131 |
|
|---|
| 132 |
@classmethod |
|---|
| 133 |
def _LogExceptionAndMessage(cls, level, format=None, *args): |
|---|
| 134 |
try: |
|---|
| 135 |
logger = logging.getLogger(u'GeoEco') |
|---|
| 136 |
|
|---|
| 137 |
|
|---|
| 138 |
|
|---|
| 139 |
tb = sys.exc_info()[2] |
|---|
| 140 |
if tb is not None: |
|---|
| 141 |
try: |
|---|
| 142 |
|
|---|
| 143 |
|
|---|
| 144 |
|
|---|
| 145 |
while tb.tb_next is not None: |
|---|
| 146 |
tb = tb.tb_next |
|---|
| 147 |
|
|---|
| 148 |
|
|---|
| 149 |
|
|---|
| 150 |
|
|---|
| 151 |
if cls._ExceptionTracebackID != id(tb): |
|---|
| 152 |
cls._ExceptionTracebackID = id(tb) |
|---|
| 153 |
cls._ReportedSubsequentErrors = False |
|---|
| 154 |
logger.log(level, u'%s: %s', unicode(sys.exc_info()[0].__name__), unicode(sys.exc_info()[1]).rstrip()) |
|---|
| 155 |
|
|---|
| 156 |
|
|---|
| 157 |
|
|---|
| 158 |
|
|---|
| 159 |
|
|---|
| 160 |
|
|---|
| 161 |
|
|---|
| 162 |
|
|---|
| 163 |
|
|---|
| 164 |
|
|---|
| 165 |
|
|---|
| 166 |
|
|---|
| 167 |
|
|---|
| 168 |
logger.debug(_(u'---------- BEGINNING OF DEBUGGING INFORMATION ----------')) |
|---|
| 169 |
logger.debug(_(u'Traceback (most recent call last):')) |
|---|
| 170 |
stackTraceEntries = traceback.extract_stack(tb.tb_frame.f_back) + traceback.extract_tb(tb) |
|---|
| 171 |
for entry in traceback.format_list(stackTraceEntries): |
|---|
| 172 |
for line in entry.split('\n'): |
|---|
| 173 |
if len(line) > 0: |
|---|
| 174 |
logger.debug(line.rstrip()) |
|---|
| 175 |
logger.debug(u'%s: %s', unicode(sys.exc_info()[0].__name__), unicode(sys.exc_info()[1]).rstrip()) |
|---|
| 176 |
|
|---|
| 177 |
|
|---|
| 178 |
|
|---|
| 179 |
|
|---|
| 180 |
frame = tb.tb_frame |
|---|
| 181 |
try: |
|---|
| 182 |
while frame is not None and (frame.f_code.co_filename.find('GeoEco') == -1 or frame.f_code.co_filename.find('AssimilatedModules') >= 0 or frame.f_code.co_filename.endswith('Logging.py') and frame.f_code.co_name == 'RaiseException' or frame.f_code.co_filename.endswith('R.py') and frame.f_code.co_name in ['__call__', '__getitem__', '__setitem__', '__delitem__', '__getattr__', '__setattr__', '__delattr__']): |
|---|
| 183 |
frame = frame.f_back |
|---|
| 184 |
if frame is None: |
|---|
| 185 |
frame = tb.tb_frame |
|---|
| 186 |
logger.debug(_(u'Local variables for stack frame: File "%(file)s", line %(line)i, in %(func)s:') % {u'file' : frame.f_code.co_filename, u'line' : frame.f_lineno, u'func' : frame.f_code.co_name}) |
|---|
| 187 |
keys = frame.f_locals.keys() |
|---|
| 188 |
keys.sort() |
|---|
| 189 |
for key in keys: |
|---|
| 190 |
logger.debug(u' %s = %s', unicode(key), repr(frame.f_locals[key])) |
|---|
| 191 |
|
|---|
| 192 |
logger.debug(_(u'Global variables for stack frame: File "%(file)s", line %(line)i, in %(func)s:') % {u'file' : frame.f_code.co_filename, u'line' : frame.f_lineno, u'func' : frame.f_code.co_name}) |
|---|
| 193 |
keys = frame.f_globals.keys() |
|---|
| 194 |
keys.sort() |
|---|
| 195 |
for key in keys: |
|---|
| 196 |
if key != '__builtins__': |
|---|
| 197 |
logger.debug(u' %s = %s', unicode(key), repr(frame.f_globals[key])) |
|---|
| 198 |
finally: |
|---|
| 199 |
del frame |
|---|
| 200 |
|
|---|
| 201 |
|
|---|
| 202 |
|
|---|
| 203 |
logger.debug(_(u'Enviornment variables:')) |
|---|
| 204 |
keys = os.environ.keys() |
|---|
| 205 |
keys.sort() |
|---|
| 206 |
for key in keys: |
|---|
| 207 |
logger.debug(u' %s = %s', unicode(key), repr(os.environ[key])) |
|---|
| 208 |
|
|---|
| 209 |
logger.debug(_(u'Other variables:')) |
|---|
| 210 |
import GeoEco |
|---|
| 211 |
logger.debug(u' GeoEco.__version__ = %s', repr(GeoEco.__version__)) |
|---|
| 212 |
logger.debug(u' sys.argv = %s', repr(sys.argv)) |
|---|
| 213 |
logger.debug(u' sys.version = %s', str(sys.version)) |
|---|
| 214 |
logger.debug(u' sys.version_info = %s', repr(sys.version_info)) |
|---|
| 215 |
logger.debug(u' sys.platform = %s', str(sys.platform)) |
|---|
| 216 |
if isinstance(sys.platform, basestring) and sys.platform.lower() == 'win32': |
|---|
| 217 |
logger.debug(u' sys.getwindowsversion() = %s', repr(sys.getwindowsversion())) |
|---|
| 218 |
logger.debug(u' os.getcwd() = %s', str(os.getcwd())) |
|---|
| 219 |
logger.debug(u' sys.path = %s', repr(sys.path)) |
|---|
| 220 |
|
|---|
| 221 |
keys = sys.modules.keys() |
|---|
| 222 |
keys.sort() |
|---|
| 223 |
logger.debug(_(u'Loaded modules: ') + u', '.join(keys)) |
|---|
| 224 |
|
|---|
| 225 |
logger.debug(_(u'---------- END OF DEBUGGING INFORMATION ----------')) |
|---|
| 226 |
finally: |
|---|
| 227 |
del tb |
|---|
| 228 |
else: |
|---|
| 229 |
cls._ExceptionTracebackID = None |
|---|
| 230 |
|
|---|
| 231 |
|
|---|
| 232 |
|
|---|
| 233 |
if format is not None: |
|---|
| 234 |
|
|---|
| 235 |
|
|---|
| 236 |
|
|---|
| 237 |
|
|---|
| 238 |
|
|---|
| 239 |
if cls._ExceptionTracebackID is not None and not cls._ReportedSubsequentErrors: |
|---|
| 240 |
logger.log(level, _(u'The following consequences resulted from the original error:')) |
|---|
| 241 |
cls._ReportedSubsequentErrors = True |
|---|
| 242 |
|
|---|
| 243 |
|
|---|
| 244 |
|
|---|
| 245 |
logger.log(level, format.rstrip(), *args) |
|---|
| 246 |
|
|---|
| 247 |
except: |
|---|
| 248 |
pass |
|---|
| 249 |
|
|---|
| 250 |
@classmethod |
|---|
| 251 |
def Initialize(cls, activateArcGISLogging=False, loggingConfigFile=None): |
|---|
| 252 |
cls.__doc__.Obj.ValidateMethodInvocation() |
|---|
| 253 |
|
|---|
| 254 |
|
|---|
| 255 |
|
|---|
| 256 |
|
|---|
| 257 |
|
|---|
| 258 |
|
|---|
| 259 |
|
|---|
| 260 |
logging._srcfile = None |
|---|
| 261 |
|
|---|
| 262 |
|
|---|
| 263 |
|
|---|
| 264 |
|
|---|
| 265 |
|
|---|
| 266 |
|
|---|
| 267 |
|
|---|
| 268 |
|
|---|
| 269 |
if not sys.modules[u'logging'].__dict__.has_key(u'GeoEco'): |
|---|
| 270 |
sys.modules[u'logging'].__dict__[u'GeoEco'] = sys.modules[u'GeoEco'] |
|---|
| 271 |
if not sys.modules[u'logging'].__dict__.has_key(u'GeoEco.Logging'): |
|---|
| 272 |
sys.modules[u'logging'].__dict__[u'GeoEco.Logging'] = sys.modules[u'GeoEco.Logging'] |
|---|
| 273 |
|
|---|
| 274 |
|
|---|
| 275 |
|
|---|
| 276 |
|
|---|
| 277 |
callersFileWarning = None |
|---|
| 278 |
if loggingConfigFile is not None: |
|---|
| 279 |
callersFileWarning = cls._InitializeLoggingFromFile(loggingConfigFile) |
|---|
| 280 |
|
|---|
| 281 |
|
|---|
| 282 |
|
|---|
| 283 |
|
|---|
| 284 |
userDefaultFile = None |
|---|
| 285 |
userDefaultFileWarning = None |
|---|
| 286 |
if loggingConfigFile is None or callersFileWarning is not None: |
|---|
| 287 |
if sys.platform.lower() == u'win32' and os.environ.has_key(u'APPDATA'): |
|---|
| 288 |
import codecs |
|---|
| 289 |
userDefaultFile = codecs.mbcs_decode(os.environ['APPDATA'])[0] + u'\\GeoEco\\Logging.ini' |
|---|
| 290 |
if userDefaultFile is not None: |
|---|
| 291 |
if os.path.isfile(userDefaultFile): |
|---|
| 292 |
userDefaultFileWarning = cls._InitializeLoggingFromFile(userDefaultFile) |
|---|
| 293 |
else: |
|---|
| 294 |
userDefaultFile = None |
|---|
| 295 |
|
|---|
| 296 |
|
|---|
| 297 |
|
|---|
| 298 |
|
|---|
| 299 |
systemDefaultFile = os.path.join(os.path.dirname(sys.modules['GeoEco.Logging'].__file__), u'Configuration', u'Logging.ini') |
|---|
| 300 |
systemDefaultFileWarning = None |
|---|
| 301 |
if (loggingConfigFile is None or callersFileWarning is not None) and (userDefaultFile is None or userDefaultFileWarning is not None): |
|---|
| 302 |
systemDefaultFileWarning = cls._InitializeLoggingFromFile(systemDefaultFile) |
|---|
| 303 |
|
|---|
| 304 |
|
|---|
| 305 |
|
|---|
| 306 |
|
|---|
| 307 |
manualInitializationWarning = None |
|---|
| 308 |
if (loggingConfigFile is None or callersFileWarning is not None) and (userDefaultFile is None or userDefaultFileWarning is not None) and systemDefaultFileWarning is not None: |
|---|
| 309 |
try: |
|---|
| 310 |
stdout_handler = logging.StreamHandler(strm=sys.stdout) |
|---|
| 311 |
stdout_handler.level = logging.INFO |
|---|
| 312 |
logging.getLogger(u'').addHandler(stdout_handler) |
|---|
| 313 |
logging.getLogger(u'').setLevel(logging.INFO) |
|---|
| 314 |
except Exception, e: |
|---|
| 315 |
manualInitializationWarning = _(u'Failed to initialize the logging system from hard-coded settings. One of the logging functions reported the error: %s: %s') % (e.__class__.__name__, unicode(e)) |
|---|
| 316 |
|
|---|
| 317 |
|
|---|
| 318 |
|
|---|
| 319 |
|
|---|
| 320 |
|
|---|
| 321 |
|
|---|
| 322 |
if manualInitializationWarning is not None: |
|---|
| 323 |
if callersFileWarning is not None: |
|---|
| 324 |
print(callersFileWarning) |
|---|
| 325 |
if userDefaultFileWarning is not None: |
|---|
| 326 |
print(userDefaultFileWarning) |
|---|
| 327 |
print(systemDefaultFileWarning) |
|---|
| 328 |
print(manualInitializationWarning) |
|---|
| 329 |
print(_(u'The logging system could not be initialized. Log messages will not be reported.')) |
|---|
| 330 |
|
|---|
| 331 |
elif loggingConfigFile is not None and callersFileWarning is None: |
|---|
| 332 |
cls.Debug(_(u'Logging system initialized from config file "%s".'), loggingConfigFile) |
|---|
| 333 |
|
|---|
| 334 |
elif userDefaultFile is not None and userDefaultFileWarning is None: |
|---|
| 335 |
if callersFileWarning is not None: |
|---|
| 336 |
cls.Warning(callersFileWarning) |
|---|
| 337 |
cls.Debug(_(u'Logging system initialized from config file "%s".'), userDefaultFile) |
|---|
| 338 |
|
|---|
| 339 |
elif systemDefaultFileWarning is None: |
|---|
| 340 |
if callersFileWarning is not None: |
|---|
| 341 |
cls.Warning(callersFileWarning) |
|---|
| 342 |
if userDefaultFileWarning is not None: |
|---|
| 343 |
cls.Warning(userDefaultFileWarning) |
|---|
| 344 |
cls.Debug(_(u'Logging system initialized from config file "%s".'), systemDefaultFile) |
|---|
| 345 |
|
|---|
| 346 |
elif manualInitializationWarning is None: |
|---|
| 347 |
if callersFileWarning is not None: |
|---|
| 348 |
cls.Warning(callersFileWarning) |
|---|
| 349 |
if userDefaultFileWarning is not None: |
|---|
| 350 |
cls.Warning(userDefaultFileWarning) |
|---|
| 351 |
cls.Warning(systemDefaultFileWarning) |
|---|
| 352 |
cls.Info(_(u'Log messages will only be sent to the console output (stdout).')) |
|---|
| 353 |
|
|---|
| 354 |
|
|---|
| 355 |
|
|---|
| 356 |
if activateArcGISLogging and (loggingConfigFile is not None and callersFileWarning is None or userDefaultFile is not None and userDefaultFileWarning is None or systemDefaultFileWarning is None): |
|---|
| 357 |
cls.ActivateArcGISLogging() |
|---|
| 358 |
|
|---|
| 359 |
@classmethod |
|---|
| 360 |
def ActivateArcGISLogging(cls): |
|---|
| 361 |
_ArcGISLoggingHandler.Activate() |
|---|
| 362 |
|
|---|
| 363 |
@classmethod |
|---|
| 364 |
def _InitializeLoggingFromFile(cls, loggingConfigFile=None): |
|---|
| 365 |
assert isinstance(loggingConfigFile, types.UnicodeType), u'loggingConfigFile must be a Unicode string' |
|---|
| 366 |
|
|---|
| 367 |
|
|---|
| 368 |
|
|---|
| 369 |
try: |
|---|
| 370 |
f = file(loggingConfigFile, u'r') |
|---|
| 371 |
except Exception, e: |
|---|
| 372 |
return(_(u'Failed to initialize logging from the config file "%(file)s". The file could not be opened. The operating system reported: %(error)s: %(msg)s') % {u'file': loggingConfigFile, u'error': e.__class__.__name__, u'msg': unicode(e)}) |
|---|
| 373 |
try: |
|---|
| 374 |
f.close() |
|---|
| 375 |
except: |
|---|
| 376 |
pass |
|---|
| 377 |
|
|---|
| 378 |
|
|---|
| 379 |
|
|---|
| 380 |
|
|---|
| 381 |
|
|---|
| 382 |
|
|---|
| 383 |
|
|---|
| 384 |
|
|---|
| 385 |
|
|---|
| 386 |
|
|---|
| 387 |
|
|---|
| 388 |
|
|---|
| 389 |
|
|---|
| 390 |
|
|---|
| 391 |
|
|---|
| 392 |
|
|---|
| 393 |
|
|---|
| 394 |
|
|---|
| 395 |
|
|---|
| 396 |
cap = _StderrCapturer() |
|---|
| 397 |
cap.Start() |
|---|
| 398 |
try: |
|---|
| 399 |
try: |
|---|
| 400 |
|
|---|
| 401 |
|
|---|
| 402 |
|
|---|
| 403 |
|
|---|
| 404 |
|
|---|
| 405 |
if globals().has_key(u'_TempHandler') and globals()[u'_TempHandler'] is not None: |
|---|
| 406 |
logging.getLogger(u'GeoEco').removeHandler(globals()[u'_TempHandler']) |
|---|
| 407 |
globals()[u'_TempHandler'].close() |
|---|
| 408 |
del globals()[u'_TempHandler'] |
|---|
| 409 |
|
|---|
| 410 |
|
|---|
| 411 |
|
|---|
| 412 |
logging.config.fileConfig(loggingConfigFile) |
|---|
| 413 |
|
|---|
| 414 |
except Exception, e: |
|---|
| 415 |
return _(u'Failed to initialize logging from the config file "%(file)s". Please verify that the contents of the config file are valid. Search the Python documentation for "logging configuration file format". In Python 2.4, the article is titled "6.29.10.2 Configuration file format". Python\'s log configuration file parser (logging.config.fileConfig) reported: %(error)s: %(msg)s') % {u'file': loggingConfigFile, u'error': e.__class__.__name__, u'msg': unicode(e)} |
|---|
| 416 |
finally: |
|---|
| 417 |
result = cap.Stop() |
|---|
| 418 |
|
|---|
| 419 |
if result is not None and len(result.strip()) > 0: |
|---|
| 420 |
result_lines = result.strip().split(u'\n') |
|---|
| 421 |
i = 1 |
|---|
| 422 |
while i < len(result_lines) and (len(result_lines[i]) == 0 or result_lines[i][0] == u' '): |
|---|
| 423 |
i = i + 1 |
|---|
| 424 |
message = u'' |
|---|
| 425 |
for j in range(i, len(result_lines)): |
|---|
| 426 |
message = message + result_lines[j] + u'\n' |
|---|
| 427 |
message = message.strip() |
|---|
| 428 |
return _(u'Failed to initialize logging from the config file "%s". Please verify that the contents of the config file are valid. Search the Python documentation for "logging configuration file format". In Python 2.4, the article is titled "6.29.10.2 Configuration file format". Python\'s log configuration file parser (logging.config.fileConfig) reported the error: %s') % (loggingConfigFile, message) |
|---|
| 429 |
|
|---|
| 430 |
|
|---|
| 431 |
|
|---|
| 432 |
return None |
|---|
| 433 |
|
|---|
| 434 |
|
|---|
| 435 |
class ProgressReporter(object): |
|---|
| 436 |
__doc__ = DynamicDocString() |
|---|
| 437 |
|
|---|
| 438 |
def __init__(self, |
|---|
| 439 |
progressMessage1=_(u'Progress report: %(elapsed)s elapsed, %(opsCompleted)i operations completed, %(perOp)s per operation, %(opsRemaining)i remaining, estimated completion time: %(etc)s.'), |
|---|
| 440 |
progressMessage2=_(u'Progress report: %(elapsed)s elapsed, %(opsCompleted)i operations completed, %(perOp)s per operation.'), |
|---|
| 441 |
completionMessage=_(u'Processing complete: %(elapsed)s elapsed, %(opsCompleted)i operations completed, %(perOp)s per operation.'), |
|---|
| 442 |
abortedMessage=_(u'Processing stopped before all operations were completed: %(elapsed)s elapsed, %(opsCompleted)i operations completed, %(perOp)s per operation, %(opsIncomplete)i operations not completed.'), |
|---|
| 443 |
loggingChannel=u'GeoEco'): |
|---|
| 444 |
|
|---|
| 445 |
self.ProgressMessage1 = progressMessage1 |
|---|
| 446 |
self.ProgressMessage2 = progressMessage2 |
|---|
| 447 |
self.CompletionMessage = completionMessage |
|---|
| 448 |
self.AbortedMessage = abortedMessage |
|---|
| 449 |
self.LoggingChannel = loggingChannel |
|---|
| 450 |
self._TotalOperations = None |
|---|
| 451 |
self._OperationsCompleted = 0 |
|---|
| 452 |
self._TimeStarted = None |
|---|
| 453 |
self._TimeCompleted = None |
|---|
| 454 |
self._ClockStarted = None |
|---|
| 455 |
self._ClockNextReportTime = None |
|---|
| 456 |
|
|---|
| 457 |
def _GetProgressMessage1(self): |
|---|
| 458 |
return self._ProgressMessage1 |
|---|
| 459 |
|
|---|
| 460 |
def _SetProgressMessage1(self, value): |
|---|
| 461 |
assert isinstance(value, (types.NoneType, types.UnicodeType)), u'ProgressMessage1 must be a Unicode string, or None.' |
|---|
| 462 |
self._ProgressMessage1 = value |
|---|
| 463 |
|
|---|
| 464 |
ProgressMessage1 = property(_GetProgressMessage1, _SetProgressMessage1, doc=DynamicDocString()) |
|---|
| 465 |
|
|---|
| 466 |
def _GetProgressMessage2(self): |
|---|
| 467 |
return self._ProgressMessage2 |
|---|
| 468 |
|
|---|
| 469 |
def _SetProgressMessage2(self, value): |
|---|
| 470 |
assert isinstance(value, (types.NoneType, types.UnicodeType)), u'ProgressMessage2 must be a Unicode string, or None.' |
|---|
| 471 |
self._ProgressMessage2 = value |
|---|
| 472 |
|
|---|
| 473 |
ProgressMessage2 = property(_GetProgressMessage2, _SetProgressMessage2, doc=DynamicDocString()) |
|---|
| 474 |
|
|---|
| 475 |
def _GetCompletionMessage(self): |
|---|
| 476 |
return self._CompletionMessage |
|---|
| 477 |
|
|---|
| 478 |
def _SetCompletionMessage(self, value): |
|---|
| 479 |
assert isinstance(value, (types.NoneType, types.UnicodeType)), u'CompletionMessage must be a Unicode string, or None.' |
|---|
| 480 |
self._CompletionMessage = value |
|---|
| 481 |
|
|---|
| 482 |
CompletionMessage = property(_GetCompletionMessage, _SetCompletionMessage, doc=DynamicDocString()) |
|---|
| 483 |
|
|---|
| 484 |
def _GetAbortedMessage(self): |
|---|
| 485 |
return self._AbortedMessage |
|---|
| 486 |
|
|---|
| 487 |
def _SetAbortedMessage(self, value): |
|---|
| 488 |
assert isinstance(value, (types.NoneType, types.UnicodeType)), u'AbortedMessage must be a Unicode string, or None.' |
|---|
| 489 |
self._AbortedMessage = value |
|---|
| 490 |
|
|---|
| 491 |
AbortedMessage = property(_GetAbortedMessage, _SetAbortedMessage, doc=DynamicDocString()) |
|---|
| 492 |
|
|---|
| 493 |
def _GetLoggingChannel(self): |
|---|
| 494 |
return self._LoggingChannel |
|---|
| 495 |
|
|---|
| 496 |
def _SetLoggingChannel(self, value): |
|---|
| 497 |
assert isinstance(value, (types.NoneType, types.UnicodeType)), u'LoggingChannel must be a Unicode string, or None.' |
|---|
| 498 |
self._LoggingChannel = value |
|---|
| 499 |
|
|---|
| 500 |
LoggingChannel = property(_GetLoggingChannel, _SetLoggingChannel, doc=DynamicDocString()) |
|---|
| 501 |
|
|---|
| 502 |
def _GetTotalOperations(self): |
|---|
| 503 |
return self._TotalOperations |
|---|
| 504 |
|
|---|
| 505 |
def _SetTotalOperations(self, value): |
|---|
| 506 |
assert value is None or (isinstance(value, types.IntType) and value >= 0), u'totalOperations must be a non-negative integer, or None' |
|---|
| 507 |
self._TotalOperations = value |
|---|
| 508 |
if self._TotalOperations is not None and self.HasStarted and self._OperationsCompleted >= self._TotalOperations: |
|---|
| 509 |
self.Stop() |
|---|
| 510 |
|
|---|
| 511 |
TotalOperations = property(_GetTotalOperations, _SetTotalOperations, doc=DynamicDocString()) |
|---|
| 512 |
|
|---|
| 513 |
def _GetOperationsCompleted(self): |
|---|
| 514 |
return self._OperationsCompleted |
|---|
| 515 |
|
|---|
| 516 |
OperationsCompleted = property(_GetOperationsCompleted, doc=DynamicDocString()) |
|---|
| 517 |
|
|---|
| 518 |
def _GetTimeStarted(self): |
|---|
| 519 |
return self._TimeStarted |
|---|
| 520 |
|
|---|
| 521 |
TimeStarted = property(_GetTimeStarted, doc=DynamicDocString()) |
|---|
| 522 |
|
|---|
| 523 |
def _GetTimeCompleted(self): |
|---|
| 524 |
return self._TimeCompleted |
|---|
| 525 |
|
|---|
| 526 |
TimeCompleted = property(_GetTimeCompleted, doc=DynamicDocString()) |
|---|
| 527 |
|
|---|
| 528 |
def _GetHasStarted(self): |
|---|
| 529 |
return self._TimeStarted is not None |
|---|
| 530 |
|
|---|
| 531 |
HasStarted = property(_GetHasStarted, doc=DynamicDocString()) |
|---|
| 532 |
|
|---|
| 533 |
def _GetHasCompleted(self): |
|---|
| 534 |
return self._TimeCompleted is not None |
|---|
| 535 |
|
|---|
| 536 |
HasCompleted = property(_GetHasCompleted, doc=DynamicDocString()) |
|---|
| 537 |
|
|---|
| 538 |
def _GetTimeElapsed(self): |
|---|
| 539 |
if self._TimeStarted is None: |
|---|
| 540 |
return None |
|---|
| 541 |
if self._TimeCompleted is None: |
|---|
| 542 |
return datetime.timedelta(seconds = time.clock() - self._ClockStarted) |
|---|
| 543 |
return self._TimeCompleted - self._TimeStarted |
|---|
| 544 |
|
|---|
| 545 |
TimeElapsed = property(_GetTimeElapsed, doc=DynamicDocString()) |
|---|
| 546 |
|
|---|
| 547 |
def Start(self, totalOperations=None): |
|---|
| 548 |
assert not self.HasStarted, u'This ProgressReporter was already started and cannot be started a second time' |
|---|
| 549 |
|
|---|
| 550 |
self.TotalOperations = totalOperations |
|---|
| 551 |
self._OperationsCompleted = 0 |
|---|
| 552 |
self._TimeStarted = datetime.datetime.now() |
|---|
| 553 |
self._ClockStarted = time.clock() |
|---|
| 554 |
self._ClockNextReportTime = self._ClockStarted + 60.0 |
|---|
| 555 |
|
|---|
| 556 |
if totalOperations == 0: |
|---|
| 557 |
self.Stop() |
|---|
| 558 |
|
|---|
| 559 |
def ReportProgress(self, operationsCompleted=1): |
|---|
| 560 |
assert self.HasStarted, u'This ProgressReporter has not been started' |
|---|
| 561 |
assert operationsCompleted >= 1, u'operationsCompelted must be greater than or equal to 1' |
|---|
| 562 |
|
|---|
| 563 |
self._OperationsCompleted += operationsCompleted |
|---|
| 564 |
|
|---|
| 565 |
if self._TotalOperations is not None and self._OperationsCompleted >= self._TotalOperations: |
|---|
| 566 |
self.Stop() |
|---|
| 567 |
return |
|---|
| 568 |
|
|---|
| 569 |
clockNow = time.clock() |
|---|
| 570 |
if clockNow >= self._ClockNextReportTime: |
|---|
| 571 |
timeElapsed = self.TimeElapsed |
|---|
| 572 |
timePerOp = timeElapsed / self._OperationsCompleted |
|---|
| 573 |
|
|---|
| 574 |
if self._TotalOperations is not None: |
|---|
| 575 |
if self._ProgressMessage1 is not None: |
|---|
| 576 |
now = datetime.datetime.now() |
|---|
| 577 |
timeOfCompletion = now + timePerOp * (self._TotalOperations - self._OperationsCompleted) |
|---|
| 578 |
if now.day == timeOfCompletion.day: |
|---|
| 579 |
etc = unicode(timeOfCompletion.strftime('%X')) |
|---|
| 580 |
else: |
|---|
| 581 |
etc = unicode(timeOfCompletion.strftime('%c')) |
|---|
| 582 |
self._Log(self._FormatProgressMessage1(timeElapsed, self._OperationsCompleted, timePerOp, self._TotalOperations - self._OperationsCompleted, etc)) |
|---|
| 583 |
|
|---|
| 584 |
elif self._ProgressMessage2 is not None: |
|---|
| 585 |
self._Log(self._FormatProgressMessage2(timeElapsed, self._OperationsCompleted, timePerOp)) |
|---|
| 586 |
|
|---|
| 587 |
self._ClockNextReportTime = clockNow + 300.0 |
|---|
| 588 |
|
|---|
| 589 |
def Stop(self): |
|---|
| 590 |
assert self.HasStarted, u'This ProgressReporter has not been started' |
|---|
| 591 |
if self.HasCompleted: |
|---|
| 592 |
return |
|---|
| 593 |
|
|---|
| 594 |
self._TimeCompleted = datetime.datetime.now() |
|---|
| 595 |
timeElapsed = self.TimeElapsed |
|---|
| 596 |
if self._OperationsCompleted > 0: |
|---|
| 597 |
timePerOp = timeElapsed / self._OperationsCompleted |
|---|
| 598 |
else: |
|---|
| 599 |
timePerOp = datetime.timedelta() |
|---|
| 600 |
if self._TotalOperations is None or self._OperationsCompleted >= self._TotalOperations: |
|---|
| 601 |
if self._CompletionMessage is not None: |
|---|
| 602 |
self._Log(self._FormatCompletionMessage(timeElapsed, self._OperationsCompleted, timePerOp)) |
|---|
| 603 |
elif self._AbortedMessage is not None: |
|---|
| 604 |
self._Log(self._FormatAbortedMessage(timeElapsed, self._OperationsCompleted, timePerOp, self._TotalOperations - self._OperationsCompleted)) |
|---|
| 605 |
|
|---|
| 606 |
def _Log(self, message): |
|---|
| 607 |
try: |
|---|
| 608 |
if self._LoggingChannel == u'GeoEco': |
|---|
| 609 |
Logger.Info(message) |
|---|
| 610 |
else: |
|---|
| 611 |
logging.getLogger(self._LoggingChannel).info(message) |
|---|
| 612 |
except: |
|---|
| 613 |
pass |
|---|
| 614 |
|
|---|
| 615 |
|
|---|
| 616 |
|
|---|
| 617 |
|
|---|
| 618 |
def _FormatProgressMessage1(self, timeElapsed, opsCompleted, timePerOp, opsRemaining, estimatedTimeOfCompletionString): |
|---|
| 619 |
return self._ProgressMessage1 % {u'elapsed' : unicode(datetime.timedelta(days=timeElapsed.days, seconds=timeElapsed.seconds)), u'opsCompleted': opsCompleted, u'perOp': unicode(timePerOp), u'opsRemaining': opsRemaining, u'etc': estimatedTimeOfCompletionString} |
|---|
| 620 |
|
|---|
| 621 |
def _FormatProgressMessage2(self, timeElapsed, opsCompleted, timePerOp): |
|---|
| 622 |
return self._ProgressMessage2 % {u'elapsed' : unicode(datetime.timedelta(days=timeElapsed.days, seconds=timeElapsed.seconds)), u'opsCompleted': opsCompleted, u'perOp': unicode(timePerOp)} |
|---|
| 623 |
|
|---|
| 624 |
def _FormatCompletionMessage(self, timeElapsed, opsCompleted, timePerOp): |
|---|
| 625 |
return self._CompletionMessage % {u'elapsed' : unicode(datetime.timedelta(days=timeElapsed.days, seconds=timeElapsed.seconds)), u'opsCompleted': opsCompleted, u'perOp': unicode(timePerOp)} |
|---|
| 626 |
|
|---|
| 627 |
def _FormatAbortedMessage(self, timeElapsed, opsCompleted, timePerOp, opsIncomplete): |
|---|
| 628 |
return self._AbortedMessage % {u'elapsed' : unicode(datetime.timedelta(days=timeElapsed.days, seconds=timeElapsed.seconds)), u'opsCompleted': opsCompleted, u'perOp': unicode(timePerOp), u'opsIncomplete': opsIncomplete} |
|---|
| 629 |
|
|---|
| 630 |
|
|---|
| 631 |
|
|---|
| 632 |
|
|---|
| 633 |
class _ArcGISLoggingHandler(logging.Handler): |
|---|
| 634 |
|
|---|
| 635 |
def __init__(self, level=logging.NOTSET): |
|---|
| 636 |
logging.Handler.__init__(self, level) |
|---|
| 637 |
|
|---|
| 638 |
def emit(self, record): |
|---|
| 639 |
if self.__class__._Instance != self: |
|---|
| 640 |
self.__class__._Instance = self |
|---|
| 641 |
if not isinstance(record, logging.LogRecord): |
|---|
| 642 |
return |
|---|
| 643 |
try: |
|---|
| 644 |
if self.__class__._PreactivationQueue is not None: |
|---|
| 645 |
if len(self.__class__._PreactivationQueue) == 1000: |
|---|
| 646 |
del self.__class__._PreactivationQueue[0] |
|---|
| 647 |
self.__class__._PreactivationQueue.append(record) |
|---|
| 648 |
else: |
|---|
| 649 |
self._Emit(record) |
|---|
| 650 |
except: |
|---|
| 651 |
pass |
|---|
| 652 |
|
|---|
| 653 |
def _Emit(self, record): |
|---|
| 654 |
try: |
|---|
| 655 |
from GeoEco.ArcGIS import GeoprocessorManager |
|---|
| 656 |
message = self.format(record) |
|---|
| 657 |
if GeoprocessorManager.GetGeoprocessorIsCOMObject(): |
|---|
| 658 |
message = UserPreferredEncodingToUnicode(message) |
|---|
| 659 |
else: |
|---|
| 660 |
message = UnicodeToUserPreferredEncoding(message) |
|---|
| 661 |
if record.levelno >= logging.ERROR: |
|---|
| 662 |
GeoprocessorManager.GetGeoprocessor().AddError(message) |
|---|
| 663 |
elif record.levelno >= logging.WARNING: |
|---|
| 664 |
GeoprocessorManager.GetGeoprocessor().AddWarning(message) |
|---|
| 665 |
else: |
|---|
| 666 |
GeoprocessorManager.GetGeoprocessor().AddMessage(message) |
|---|
| 667 |
except: |
|---|
| 668 |
pass |
|---|
| 669 |
|
|---|
| 670 |
@classmethod |
|---|
| 671 |
def GetInstance(cls): |
|---|
| 672 |
return _ArcGISLoggingHandler._Instance |
|---|
| 673 |
|
|---|
| 674 |
@classmethod |
|---|
| 675 |
def Activate(cls): |
|---|
| 676 |
if cls._PreactivationQueue is not None: |
|---|
| 677 |
from GeoEco.ArcGIS import GeoprocessorManager |
|---|
| 678 |
if GeoprocessorManager.GetGeoprocessor() is None: |
|---|
| 679 |
GeoprocessorManager.InitializeGeoprocessor() |
|---|
| 680 |
if GeoprocessorManager.GetArcGISMajorVersion() == 9 and GeoprocessorManager.GetArcGISMinorVersion() == 3 and GeoprocessorManager.GetArcGISServicePack() == 0: |
|---|
| 681 |
_GeoEcoStreamHandler.Deactivate() |
|---|
| 682 |
while len(cls._PreactivationQueue) > 0: |
|---|
| 683 |
record = cls._PreactivationQueue.pop(0) |
|---|
| 684 |
cls._Instance._Emit(record) |
|---|
| 685 |
del record |
|---|
| 686 |
cls._PreactivationQueue = None |
|---|
| 687 |
|
|---|
| 688 |
_Instance = None |
|---|
| 689 |
_PreactivationQueue = [] |
|---|
| 690 |
|
|---|
| 691 |
|
|---|
| 692 |
class _GeoEcoStreamHandler(logging.StreamHandler): |
|---|
| 693 |
|
|---|
| 694 |
def __init__(self, strm=None): |
|---|
| 695 |
logging.StreamHandler.__init__(self, strm) |
|---|
| 696 |
|
|---|
| 697 |
def emit(self, record): |
|---|
| 698 |
if not _GeoEcoStreamHandler._Deactivated: |
|---|
| 699 |
logging.StreamHandler.emit(self, record) |
|---|
| 700 |
|
|---|
| 701 |
@classmethod |
|---|
| 702 |
def Deactivate(cls): |
|---|
| 703 |
_GeoEcoStreamHandler._Deactivated = True |
|---|
| 704 |
|
|---|
| 705 |
_Deactivated = False |
|---|
| 706 |
|
|---|
| 707 |
|
|---|
| 708 |
class _StderrCapturer(object): |
|---|
| 709 |
|
|---|
| 710 |
def __init__(self): |
|---|
| 711 |
self._Buffer = None |
|---|
| 712 |
self._OriginalStderr = None |
|---|
| 713 |
|
|---|
| 714 |
def Start(self): |
|---|
| 715 |
if self._OriginalStderr is None: |
|---|
| 716 |
self._Buffer = None |
|---|
| 717 |
self._OriginalStderr = sys.stderr |
|---|
| 718 |
sys.stderr = self |
|---|
| 719 |
|
|---|
| 720 |
def write(self, obj): |
|---|
| 721 |
if self._OriginalStderr is not None: |
|---|
| 722 |
if self._Buffer is None: |
|---|
| 723 |
self._Buffer = unicode(obj) |
|---|
| 724 |
else: |
|---|
| 725 |
self._Buffer = self._Buffer + unicode(obj) |
|---|
| 726 |
|
|---|
| 727 |
def Stop(self): |
|---|
| 728 |
if self._OriginalStderr is not None: |
|---|
| 729 |
sys.stderr = self._OriginalStderr |
|---|
| 730 |
self._OriginalStderr = None |
|---|
| 731 |
return self._Buffer |
|---|
| 732 |
else: |
|---|
| 733 |
return None |
|---|
| 734 |
|
|---|
| 735 |
|
|---|
| 736 |
|
|---|
| 737 |
|
|---|
| 738 |
|
|---|
| 739 |
|
|---|
| 740 |
|
|---|
| 741 |
|
|---|
| 742 |
|
|---|
| 743 |
_TempHandler = None |
|---|
| 744 |
try: |
|---|
| 745 |
if _ArcGISLoggingHandler.GetInstance() is None: |
|---|
| 746 |
_TempHandler = _ArcGISLoggingHandler(logging.INFO) |
|---|
| 747 |
_logger = logging.getLogger(u'GeoEco') |
|---|
| 748 |
if _logger is not None: |
|---|
| 749 |
_logger.addHandler(_TempHandler) |
|---|
| 750 |
del _logger |
|---|
| 751 |
except: |
|---|
| 752 |
pass |
|---|
| 753 |
|
|---|
| 754 |
|
|---|
| 755 |
|
|---|
| 756 |
|
|---|
| 757 |
|
|---|
| 758 |
|
|---|
| 759 |
from GeoEco.Metadata import * |
|---|
| 760 |
from GeoEco.Types import * |
|---|
| 761 |
|
|---|
| 762 |
AddModuleMetadata(shortDescription=_(u'Implements the Logger class, which other GeoEco classes use to report activity to the user.')) |
|---|
| 763 |
|
|---|
| 764 |
|
|---|
| 765 |
|
|---|
| 766 |
|
|---|
| 767 |
|
|---|
| 768 |
AddClassMetadata(Logger, |
|---|
| 769 |
shortDescription=_(u'Provides methods for reporting messages to the user.'), |
|---|
| 770 |
isExposedAsCOMServer=True, |
|---|
| 771 |
comIID=u'{0DA39145-CDE6-48F2-AFD9-8EA6623A3121}', |
|---|
| 772 |
comCLSID=u'{EE5ED6B5-55E7-4D65-B627-EF062B8332C4}') |
|---|
| 773 |
|
|---|
| 774 |
|
|---|
| 775 |
|
|---|
| 776 |
AddPropertyMetadata(Logger.LogInfoAsDebug, |
|---|
| 777 |
typeMetadata=BooleanTypeMetadata(), |
|---|
| 778 |
shortDescription=_(u'If True, informational messages will be logged as debug messages.'), |
|---|
| 779 |
longDescription=_( |
|---|
| 780 |
u"""Informational messages describe major processing steps that may be |
|---|
| 781 |
interesting to the user but do not require the user to take any |
|---|
| 782 |
action. For example, a method that performs three major processing |
|---|
| 783 |
tasks might report an informational message after each step is |
|---|
| 784 |
finished. |
|---|
| 785 |
|
|---|
| 786 |
Sometimes your method may repeatedly call another method to accomplish |
|---|
| 787 |
some processing that you consider to be relatively unimportant. For |
|---|
| 788 |
example, your method may copy a bunch of files, and you might want to |
|---|
| 789 |
inform the user that you are performing the copying but do not want to |
|---|
| 790 |
inform them about every file. In this situation, set this property to |
|---|
| 791 |
True prior to entering the copy loop, and restore it to False when you |
|---|
| 792 |
are done."""), |
|---|
| 793 |
isExposedToPythonCallers=True, |
|---|
| 794 |
isExposedByCOM=True) |
|---|
| 795 |
|
|---|
| 796 |
AddPropertyMetadata(Logger.LogErrorsAsWarnings, |
|---|
| 797 |
typeMetadata=BooleanTypeMetadata(), |
|---|
| 798 |
shortDescription=_(u'If True, errors will be logged as warning messages.'), |
|---|
| 799 |
longDescription=_( |
|---|
| 800 |
u"""Error messages describe failures that halt processing and require the user |
|---|
| 801 |
to fix a problem and restart processing. ArcGIS highlights error messages in red |
|---|
| 802 |
in its user interface, and fails geoprocessing if even one error is reported. |
|---|
| 803 |
|
|---|
| 804 |
Sometimes you don't want to halt processing when an unimportant operation fails. |
|---|
| 805 |
For example, you may not care that a temporary file could not be deleted. In |
|---|
| 806 |
that situation, set this property to True prior to calling File.Delete to delete |
|---|
| 807 |
the file. If the deletion fails, the errors that occur will be logged as |
|---|
| 808 |
warnings rather than errors, and processing will not be halted. After |
|---|
| 809 |
File.Delete returns, set this property back to False, so that subsequent errors |
|---|
| 810 |
will be logged as errors."""), |
|---|
| 811 |
isExposedToPythonCallers=True, |
|---|
| 812 |
isExposedByCOM=True) |
|---|
| 813 |
|
|---|
| 814 |
|
|---|
| 815 |
|
|---|
| 816 |
AddMethodMetadata(Logger.Debug, |
|---|
| 817 |
shortDescription=_(u'Reports a debugging message to the user.'), |
|---|
| 818 |
longDescription=_( |
|---|
| 819 |
u"""Like the C printf function or the Python % operator, this method generates a |
|---|
| 820 |
message string by merging in the optional arguments into the format string. |
|---|
| 821 |
|
|---|
| 822 |
Debugging messages describe processing details that are usually not interesting |
|---|
| 823 |
unless the user is diagnosing a problem. The default configuration of the |
|---|
| 824 |
logging system causes debugging messages to be discarded."""), |
|---|
| 825 |
isExposedToPythonCallers=True, |
|---|
| 826 |
isExposedByCOM=True) |
|---|
| 827 |
|
|---|
| 828 |
AddArgumentMetadata(Logger.Debug, u'cls', |
|---|
| 829 |
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=Logger), |
|---|
| 830 |
description=_(u'%s class or an instance of it.') % Logger.__name__) |
|---|
| 831 |
|
|---|
| 832 |
AddArgumentMetadata(Logger.Debug, u'format', |
|---|
| 833 |
typeMetadata=UnicodeStringTypeMetadata(), |
|---|
| 834 |
description=_( |
|---|
| 835 |
u"""A printf-style format string. While Unicode strings are encouraged, this |
|---|
| 836 |
method will also accept an 8-bit string for this parameter. For a complete |
|---|
| 837 |
specification of the format of this string, look up "% formatting" in the Python |
|---|
| 838 |
documentation.""")) |
|---|
| 839 |
|
|---|
| 840 |
AddArgumentMetadata(Logger.Debug, u'args', |
|---|
| 841 |
typeMetadata=TupleTypeMetadata(elementType=AnyObjectTypeMetadata(canBeNone=True)), |
|---|
| 842 |
description=_(u'Values to insert into the format string.')) |
|---|
| 843 |
|
|---|
| 844 |
|
|---|
| 845 |
|
|---|
| 846 |
AddMethodMetadata(Logger.Info, |
|---|
| 847 |
shortDescription=_(u'Reports an informational message to the user.'), |
|---|
| 848 |
longDescription=_( |
|---|
| 849 |
u"""Like the C printf function or the Python % operator, this method generates a |
|---|
| 850 |
message string by merging in the optional arguments into the format string. |
|---|
| 851 |
|
|---|
| 852 |
Informational messages describe major processing steps that may be interesting to |
|---|
| 853 |
the user but do not require the user to take any action. For example, a method |
|---|
| 854 |
that performs three major processing tasks might report an informational message |
|---|
| 855 |
after each step is finished. Do not report too many informational messages or |
|---|
| 856 |
you may overwhelm the user. Report processing details as debug messages."""), |
|---|
| 857 |
isExposedToPythonCallers=True, |
|---|
| 858 |
isExposedByCOM=True) |
|---|
| 859 |
|
|---|
| 860 |
AddArgumentMetadata(Logger.Info, u'cls', |
|---|
| 861 |
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=Logger), |
|---|
| 862 |
description=Logger.Debug.__doc__.Obj.Arguments[0].Description) |
|---|
| 863 |
|
|---|
| 864 |
AddArgumentMetadata(Logger.Info, u'format', |
|---|
| 865 |
typeMetadata=UnicodeStringTypeMetadata(), |
|---|
| 866 |
description=Logger.Debug.__doc__.Obj.Arguments[1].Description) |
|---|
| 867 |
|
|---|
| 868 |
AddArgumentMetadata(Logger.Info, u'args', |
|---|
| 869 |
typeMetadata=TupleTypeMetadata(elementType=AnyObjectTypeMetadata(canBeNone=True)), |
|---|
| 870 |
description=Logger.Debug.__doc__.Obj.Arguments[2].Description) |
|---|
| 871 |
|
|---|
| 872 |
|
|---|
| 873 |
|
|---|
| 874 |
AddMethodMetadata(Logger.Warning, |
|---|
| 875 |
shortDescription=_(u'Reports a warning message to the user.'), |
|---|
| 876 |
longDescription=_( |
|---|
| 877 |
u"""Like the C printf function or the Python % operator, this method generates a |
|---|
| 878 |
message string by merging in the optional arguments into the format string. |
|---|
| 879 |
|
|---|
| 880 |
Warning messages describe important events that should be brought to the user's |
|---|
| 881 |
attention but do not necessarily indicate that processing will fail. To draw the |
|---|
| 882 |
user's attention, ArcGIS highlights warning messages in green in its user |
|---|
| 883 |
interface. |
|---|
| 884 |
|
|---|
| 885 |
*Note to GeoEco developers:* Do not call this method to report exceptions caught |
|---|
| 886 |
inside methods of GeoEco classes. Call LogExceptionAsWarning instead."""), |
|---|
| 887 |
isExposedToPythonCallers=True, |
|---|
| 888 |
isExposedByCOM=True) |
|---|
| 889 |
|
|---|
| 890 |
AddArgumentMetadata(Logger.Warning, u'cls', |
|---|
| 891 |
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=Logger), |
|---|
| 892 |
description=Logger.Debug.__doc__.Obj.Arguments[0].Description) |
|---|
| 893 |
|
|---|
| 894 |
AddArgumentMetadata(Logger.Warning, u'format', |
|---|
| 895 |
typeMetadata=UnicodeStringTypeMetadata(), |
|---|
| 896 |
description=Logger.Debug.__doc__.Obj.Arguments[1].Description) |
|---|
| 897 |
|
|---|
| 898 |
AddArgumentMetadata(Logger.Warning, u'args', |
|---|
| 899 |
typeMetadata=TupleTypeMetadata(elementType=AnyObjectTypeMetadata(canBeNone=True)), |
|---|
| 900 |
description=Logger.Debug.__doc__.Obj.Arguments[2].Description) |
|---|
| 901 |
|
|---|
| 902 |
|
|---|
| 903 |
|
|---|
| 904 |
AddMethodMetadata(Logger.Error, |
|---|
| 905 |
shortDescription=_(u'Reports an error message to the user.'), |
|---|
| 906 |
longDescription=_( |
|---|
| 907 |
u"""Like the C printf function or the Python % operator, this method generates a |
|---|
| 908 |
message string by merging in the optional arguments into the format string. |
|---|
| 909 |
|
|---|
| 910 |
Error messages describe failures that halt processing and require the user to |
|---|
| 911 |
fix a problem and restart processing. ArcGIS highlights error messages in red in |
|---|
| 912 |
its user interface, and fails geoprocessing if even one error is reported. |
|---|
| 913 |
Because of this, do not report error messages unless the problem is serious |
|---|
| 914 |
enough to stop processing. For problems that may or may not be of consequence to |
|---|
| 915 |
the user, report warning messages. |
|---|
| 916 |
|
|---|
| 917 |
If LogWarningsAsErrors has been set to True, the message will be reported as a |
|---|
| 918 |
warning rather than an error. |
|---|
| 919 |
|
|---|
| 920 |
*Note to GeoEco developers:* Do not call this method to report exceptions caught |
|---|
| 921 |
inside methods of GeoEco classes. Call LogExceptionAsError instead."""), |
|---|
| 922 |
isExposedToPythonCallers=True, |
|---|
| 923 |
isExposedByCOM=True) |
|---|
| 924 |
|
|---|
| 925 |
AddArgumentMetadata(Logger.Error, u'cls', |
|---|
| 926 |
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=Logger), |
|---|
| 927 |
description=Logger.Debug.__doc__.Obj.Arguments[0].Description) |
|---|
| 928 |
|
|---|
| 929 |
AddArgumentMetadata(Logger.Error, u'format', |
|---|
| 930 |
typeMetadata=UnicodeStringTypeMetadata(), |
|---|
| 931 |
description=Logger.Debug.__doc__.Obj.Arguments[1].Description) |
|---|
| 932 |
|
|---|
| 933 |
AddArgumentMetadata(Logger.Error, u'args', |
|---|
| 934 |
typeMetadata=TupleTypeMetadata(elementType=AnyObjectTypeMetadata(canBeNone=True)), |
|---|
| 935 |
description=Logger.Debug.__doc__.Obj.Arguments[2].Description) |
|---|
| 936 |
|
|---|
| 937 |
|
|---|
| 938 |
|
|---|
| 939 |
AddMethodMetadata(Logger.LogInfoAndSetInfoToDebug, |
|---|
| 940 |
shortDescription=_(u'Reports an informational message, sets the LogInfoAsDebug property to True, and returns its previous value.'), |
|---|
| 941 |
longDescription=_( |
|---|
| 942 |
u"""This function is used to efficiently implement a common logging |
|---|
| 943 |
scenario: a function wants to log one informational message announcing |
|---|
| 944 |
the processing it is doing and report everything else as debug |
|---|
| 945 |
messages, including informational messages reported by nested |
|---|
| 946 |
functions. The Python pattern for implementing this scenario is:: |
|---|
| 947 |
|
|---|
| 948 |
from GeoEco.Internationalization import _ |
|---|
| 949 |
from GeoEco.Logging import Logger |
|---|
| 950 |
|
|---|
| 951 |
def MyFunc(...): |
|---|
| 952 |
oldLogInfoAsDebug = Logger.LogInfoAndSetInfoToDebug(_(u'Doing my processing...')) |
|---|
| 953 |
try: |
|---|
| 954 |
... |
|---|
| 955 |
finally: |
|---|
| 956 |
Logger.SetLogInfoAsDebug(oldLogInfoAsDebug) |
|---|
| 957 |
"""), |
|---|
| 958 |
isExposedToPythonCallers=True, |
|---|
| 959 |
isExposedByCOM=True) |
|---|
| 960 |
|
|---|
| 961 |
CopyArgumentMetadata(Logger.Info, u'cls', Logger.LogInfoAndSetInfoToDebug, u'cls') |
|---|
| 962 |
CopyArgumentMetadata(Logger.Info, u'format', Logger.LogInfoAndSetInfoToDebug, u'format') |
|---|
| 963 |
CopyArgumentMetadata(Logger.Info, u'args', Logger.LogInfoAndSetInfoToDebug, u'args') |
|---|
| 964 |
|
|---|
| 965 |
AddResultMetadata(Logger.LogInfoAndSetInfoToDebug, u'oldLogInfoAsDebug', |
|---|
| 966 |
typeMetadata=BooleanTypeMetadata(), |
|---|
| 967 |
description=_(u"""The old value of the LogInfoAsDebug property, prior to this method being invoked.""")) |
|---|
| 968 |
|
|---|
| 969 |
|
|---|
| 970 |
|
|---|
| 971 |
AddMethodMetadata(Logger.RaiseException, |
|---|
| 972 |
shortDescription=_(u'Raises a Python exception and logs it as an error message and additional information as debug messages.'), |
|---|
| 973 |
longDescription=_( |
|---|
| 974 |
u"""GeoEco classes should not raise exceptions by calling the Python raise |
|---|
| 975 |
statement directly, but should call this method instead. This method will raise |
|---|
| 976 |
the exception, log it as an error (or warning, if LogWarningsAsErrors has been |
|---|
| 977 |
set to True), and also log a bunch of debugging information as debug messages.""")) |
|---|
| 978 |
|
|---|
| 979 |
AddArgumentMetadata(Logger.RaiseException, u'cls', |
|---|
| 980 |
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=Logger), |
|---|
| 981 |
description=Logger.Debug.__doc__.Obj.Arguments[0].Description) |
|---|
| 982 |
|
|---|
| 983 |
AddArgumentMetadata(Logger.RaiseException, u'exception', |
|---|
| 984 |
typeMetadata=ClassInstanceTypeMetadata(cls=Exception), |
|---|
| 985 |
description=_(u'The Python exception instance to raise.')) |
|---|
| 986 |
|
|---|
| 987 |
|
|---|
| 988 |
|
|---|
| 989 |
AddMethodMetadata(Logger.LogExceptionAsWarning, |
|---|
| 990 |
shortDescription=_(u'Logs a Python exception caught by a GeoEco class as a warning message and additional information as debug messages.'), |
|---|
| 991 |
longDescription=_( |
|---|
| 992 |
u"""GeoEco classes should use LogExceptionAsWarning or LogExceptionAsError to |
|---|
| 993 |
report exceptions caught by except clauses of try statements, like this:: |
|---|
| 994 |
|
|---|
| 995 |
Logger.Debug(_(u'Copying file %s to %s.') % (sourceFile, destinationFile)) |
|---|
| 996 |
try: |
|---|
| 997 |
shutil.copy2(sourceFile, destinationFile) |
|---|
| 998 |
except: |
|---|
| 999 |
Logger.LogExceptionAsError(_(u'Could not copy file %(source)s to %(dest)s.') % \\ |
|---|
| 1000 |
{u'source' : sourceFile, u'dest' : destinationFile}) |
|---|
| 1001 |
raise |
|---|
| 1002 |
|
|---|
| 1003 |
As shown, the except clause should re-raise the exception (if appropriate) using |
|---|
| 1004 |
a raise statement with no parameters. LogExceptionAsWarning and |
|---|
| 1005 |
LogExceptionAsError will log the exception and some debugging information, |
|---|
| 1006 |
including a stack trace. If the caller provides the optional format string, it |
|---|
| 1007 |
is logged as a "consequence" of the original error. For example the code above |
|---|
| 1008 |
produces the following output when the caller does not have permission to write |
|---|
| 1009 |
the destination file:: |
|---|
| 1010 |
|
|---|
| 1011 |
DEBUG Copying file c:\\foo.txt to c:\\bar.txt. |
|---|
| 1012 |
ERROR IOError: [Errno 13] Permission denied: u'c:\\\\bar.txt' |
|---|
| 1013 |
DEBUG ---------- BEGINNING OF DEBUGGING INFORMATION ---------- |
|---|
| 1014 |
DEBUG Traceback (most recent call last): |
|---|
| 1015 |
DEBUG File "<stdin>", line 1, in ? |
|---|
| 1016 |
DEBUG File "<stdin>", line 2, in tryit |
|---|
| 1017 |
DEBUG File "C:\\Python24\\Lib\\site-packages\\GeoEco\\FileSystemUtils.py", line 47, in CopyFile |
|---|
| 1018 |
DEBUG shutil.copy2(sourceFile, destinationFile) |
|---|
| 1019 |
DEBUG File "C:\\Python24\\lib\\shutil.py", line 92, in copy2 |
|---|
| 1020 |
DEBUG copyfile(src, dst) |
|---|
| 1021 |
DEBUG File "C:\\Python24\\lib\\shutil.py", line 48, in copyfile |
|---|
| 1022 |
DEBUG fdst = open(dst, 'wb') |
|---|
| 1023 |
DEBUG IOError: [Errno 13] Permission denied: u'c:\\\\bar.txt' |
|---|
| 1024 |
DEBUG End of traceback. Logging other useful debugging information... |
|---|
| 1025 |
DEBUG sys.argv = [''] |
|---|
| 1026 |
DEBUG sys.version = 2.4.4 (#71, Oct 18 2006, 08:34:43) [MSC v.1310 32 bit (Intel)] |
|---|
| 1027 |
DEBUG sys.version_info = (2, 4, 4, 'final', 0) |
|---|
| 1028 |
DEBUG sys.platform = win32 |
|---|
| 1029 |
DEBUG sys.getwindowsversion() = (5, 1, 2600, 2, 'Service Pack 2') |
|---|
| 1030 |
DEBUG ... |
|---|
| 1031 |
DEBUG ---------- END OF DEBUGGING INFORMATION ---------- |
|---|
| 1032 |
ERROR The following consequences resulted from the original error: |
|---|
| 1033 |
ERROR Could not copy file c:\\foo.txt to c:\\bar.txt. |
|---|
| 1034 |
|
|---|
| 1035 |
Unless the user has debugging messages turned on, they will only see the warning |
|---|
| 1036 |
and error messages in the log:: |
|---|
| 1037 |
|
|---|
| 1038 |
ERROR IOError: [Errno 13] Permission denied: u'c:\\\\bar.txt' |
|---|
| 1039 |
ERROR The following consequences resulted from the original error: |
|---|
| 1040 |
ERROR Could not copy file c:\\foo.txt to c:\\bar2\\bar.txt. |
|---|
| 1041 |
|
|---|
| 1042 |
Except clauses higher on the stack can also call LogExceptionAsWarning and |
|---|
| 1043 |
LogExceptionAsError. The methods keep track of whether the original exception |
|---|
| 1044 |
was logged and will not log it a second time. Instead they will just log the |
|---|
| 1045 |
optional format string, if provided, as a subsequent "consequence" of the |
|---|
| 1046 |
original exception. This allows nested methods to illustrate how the low-level |
|---|
| 1047 |
failure causes a problem in the high-level operation the user actually cares |
|---|
| 1048 |
about. For example, if the output file from a function cannot be copied from a |
|---|
| 1049 |
temporary location because a directory cannot be created, the log might look |
|---|
| 1050 |
like this:: |
|---|
| 1051 |
|
|---|
| 1052 |
ERROR IOError: [Errno 13] Permission denied: u'c:\\\\output' |
|---|
| 1053 |
ERROR The following consequences resulted from the original error: |
|---|
| 1054 |
ERROR Could create directory c:\\output. |
|---|
| 1055 |
ERROR Could not copy file c:\\processing\\results.txt to c:\\output\\results.txt. |
|---|
| 1056 |
ERROR Could not copy the results to the output directory.""")) |
|---|
| 1057 |
|
|---|
| 1058 |
AddArgumentMetadata(Logger.LogExceptionAsWarning, u'cls', |
|---|
| 1059 |
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=Logger), |
|---|
| 1060 |
description=Logger.Debug.__doc__.Obj.Arguments[0].Description) |
|---|
| 1061 |
|
|---|
| 1062 |
AddArgumentMetadata(Logger.LogExceptionAsWarning, u'format', |
|---|
| 1063 |
typeMetadata=UnicodeStringTypeMetadata(canBeNone=True), |
|---|
| 1064 |
description=Logger.Debug.__doc__.Obj.Arguments[1].Description) |
|---|
| 1065 |
|
|---|
| 1066 |
AddArgumentMetadata(Logger.LogExceptionAsWarning, u'args', |
|---|
| 1067 |
typeMetadata=TupleTypeMetadata(elementType=AnyObjectTypeMetadata(canBeNone=True)), |
|---|
| 1068 |
description=Logger.Debug.__doc__.Obj.Arguments[2].Description) |
|---|
| 1069 |
|
|---|
| 1070 |
|
|---|
| 1071 |
|
|---|
| 1072 |
AddMethodMetadata(Logger.LogExceptionAsError, |
|---|
| 1073 |
shortDescription=_(u'Logs a Python exception caught by a GeoEco class as an error message and additional information as debug messages.'), |
|---|
| 1074 |
longDescription=Logger.LogExceptionAsWarning.__doc__.Obj.LongDescription) |
|---|
| 1075 |
|
|---|
| 1076 |
AddArgumentMetadata(Logger.LogExceptionAsError, u'cls', |
|---|
| 1077 |
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=Logger), |
|---|
| 1078 |
description=Logger.LogExceptionAsWarning.__doc__.Obj.Arguments[0].Description) |
|---|
| 1079 |
|
|---|
| 1080 |
AddArgumentMetadata(Logger.LogExceptionAsError, u'format', |
|---|
| 1081 |
typeMetadata=UnicodeStringTypeMetadata(canBeNone=True), |
|---|
| 1082 |
description=Logger.LogExceptionAsWarning.__doc__.Obj.Arguments[1].Description) |
|---|
| 1083 |
|
|---|
| 1084 |
AddArgumentMetadata(Logger.LogExceptionAsError, u'args', |
|---|
| 1085 |
typeMetadata=TupleTypeMetadata(elementType=AnyObjectTypeMetadata(canBeNone=True)), |
|---|
| 1086 |
description=Logger.LogExceptionAsWarning.__doc__.Obj.Arguments[2].Description) |
|---|
| 1087 |
|
|---|
| 1088 |
|
|---|
| 1089 |
|
|---|
| 1090 |
AddMethodMetadata(Logger.Initialize, |
|---|
| 1091 |
shortDescription=_(u'Initializes the logging system.'), |
|---|
| 1092 |
isExposedToPythonCallers=True, |
|---|
| 1093 |
isExposedByCOM=True) |
|---|
| 1094 |
|
|---|
| 1095 |
AddArgumentMetadata(Logger.Initialize, u'cls', |
|---|
| 1096 |
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=Logger), |
|---|
| 1097 |
description=Logger.Debug.__doc__.Obj.Arguments[0].Description) |
|---|
| 1098 |
|
|---|
| 1099 |
AddArgumentMetadata(Logger.Initialize, u'activateArcGISLogging', |
|---|
| 1100 |
typeMetadata=BooleanTypeMetadata(), |
|---|
| 1101 |
description=_( |
|---|
| 1102 |
u"""If true, logging messages will be delivered to the ArcGIS geoprocessing |
|---|
| 1103 |
system and appear in the ArcGIS user interface. If false, they will be reported |
|---|
| 1104 |
to other logging destinations but will be queued in memory for ArcGIS until the |
|---|
| 1105 |
ActivateArcGISLogging method is called. To limit memory consumption in the event |
|---|
| 1106 |
that the method is never called, the queue retains only the most recent 1000 |
|---|
| 1107 |
messages. If you are calling Initialize but not running as part of an ArcGIS |
|---|
| 1108 |
geoprocessing *do not* pass true for this parameter. Passing true will decrease |
|---|
| 1109 |
performance by initializing the ArcGIS geoprocessor when it might not be |
|---|
| 1110 |
necessary to do so. (The memory used by the queue is negligible.)""")) |
|---|
| 1111 |
|
|---|
| 1112 |
AddArgumentMetadata(Logger.Initialize, u'loggingConfigFile', |
|---|
| 1113 |
typeMetadata=FileTypeMetadata(canBeNone=True, mustExist=True), |
|---|
| 1114 |
description=_( |
|---|
| 1115 |
u"""Path to the logging configuration file. If not provided, this |
|---|
| 1116 |
function attempts to load a configuration file from these two |
|---|
| 1117 |
locations: |
|---|
| 1118 |
|
|---|
| 1119 |
* The file %APPDATA%\\\\GeoEco\\\\Logging.ini (e.g. |
|---|
| 1120 |
C:\\\\Documents and Settings\\\\Jason\\\\Application Data\\\\GeoEco\\\\Logging.ini). |
|---|
| 1121 |
This allows each user to configure their own default logging settings. |
|---|
| 1122 |
|
|---|
| 1123 |
* The file Logging.ini in the Configuration subdirectory of the GeoEco |
|---|
| 1124 |
Python package installation directory (e.g. |
|---|
| 1125 |
C:\\\\Python24\\\\lib\\\\site-packages\\\\GeoEco\\\\Configuration\\\\Logging.ini). |
|---|
| 1126 |
These settings will be used if the user does not specify their own |
|---|
| 1127 |
Logging.ini file. |
|---|
| 1128 |
|
|---|
| 1129 |
If neither is found (which would only occur if the GeoEco package |
|---|
| 1130 |
installation is corrupt), then all INFO, WARNING, and ERROR messages |
|---|
| 1131 |
will be logged to the console (i.e. the stdout stream).""")) |
|---|
| 1132 |
|
|---|
| 1133 |
|
|---|
| 1134 |
|
|---|
| 1135 |
|
|---|
| 1136 |
|
|---|
| 1137 |
AddClassMetadata(ProgressReporter, |
|---|
| 1138 |
shortDescription=_(u'Provides a simple mechanism for long-running operations to report periodic progress to the user.'), |
|---|
| 1139 |
longDescription=_( |
|---|
| 1140 |
u"""This class provides progress-reporting capability for two kinds of |
|---|
| 1141 |
long-running operations: those for which the total number of |
|---|
| 1142 |
sub-operations is known when the long-running operation is started, |
|---|
| 1143 |
and those for which the total number of sub-operations cannot be |
|---|
| 1144 |
determined. In both cases, this class periodically reports the elapsed |
|---|
| 1145 |
time, the number of completed sub-operations, and the average time per |
|---|
| 1146 |
sub-operation. If the number of sub-operations is known, this class |
|---|
| 1147 |
also reports the number of sub-operations remaining and the estimated |
|---|
| 1148 |
time of completion. |
|---|
| 1149 |
|
|---|
| 1150 |
When the total number of sub-operations is known, use this class like |
|---|
| 1151 |
this:: |
|---|
| 1152 |
|
|---|
| 1153 |
operations = [...] # List of operations to perform |
|---|
| 1154 |
progressReporter = ProgressReporter() |
|---|
| 1155 |
progressReporter.Start(len(operations)) |
|---|
| 1156 |
for op in operations: |
|---|
| 1157 |
... # Do one operation |
|---|
| 1158 |
progressReporter.ReportProgress() |
|---|
| 1159 |
|
|---|
| 1160 |
When the total number of sub-operations is not known, use this class |
|---|
| 1161 |
like this:: |
|---|
| 1162 |
|
|---|
| 1163 |
progressReporter = ProgressReporter() |
|---|
| 1164 |
progressReporter.Start() |
|---|
| 1165 |
while True: |
|---|
| 1166 |
... # Do one operation or exit loop if done |
|---|
| 1167 |
progressReporter.ReportProgress() |
|---|
| 1168 |
progressReporter.Stop() |
|---|
| 1169 |
|
|---|
| 1170 |
The ReportProgress method will report the first message after |
|---|
| 1171 |
one minute and an additional message every five minutes thereafter. A |
|---|
| 1172 |
message will also be reported when processing is complete, by |
|---|
| 1173 |
ReportProgress in the first scenario and Stop in the second scenario. |
|---|
| 1174 |
You can configure the format of the progress messages by setting the |
|---|
| 1175 |
ProgressMessage1, ProgressMessage2, and CompletionMessage properties. |
|---|
| 1176 |
All messages are reported at the Info logging level. You can configure |
|---|
| 1177 |
the logging channel that is used to report the messages by setting the |
|---|
| 1178 |
LoggingChannel property.""")) |
|---|
| 1179 |
|
|---|
| 1180 |
|
|---|
| 1181 |
|
|---|
| 1182 |
AddPropertyMetadata(ProgressReporter.ProgressMessage1, |
|---|
| 1183 |
typeMetadata=UnicodeStringTypeMetadata(), |
|---|
| 1184 |
shortDescription=_(u'printf-style format string for periodically reporting progress when the total number of sub-operations is known a priori.'), |
|---|
| 1185 |
longDescription=_( |
|---|
| 1186 |
u"""Your string must include all five format specifiers, as is done in |
|---|
| 1187 |
this example:: |
|---|
| 1188 |
|
|---|
| 1189 |
u'Progress report: %(elapsed)s elapsed, %(opsCompleted)i operations completed, %(perOp)s per operation, %(opsRemaining)i remaining, estimated completion time: %(etc)s.' |
|---|
| 1190 |
"""), |
|---|
| 1191 |
isExposedToPythonCallers=True) |
|---|
| 1192 |
|
|---|
| 1193 |
AddPropertyMetadata(ProgressReporter.ProgressMessage2, |
|---|
| 1194 |
typeMetadata=UnicodeStringTypeMetadata(), |
|---|
| 1195 |
shortDescription=_(u'printf-style format string for periodically reporting progress when the total number of sub-operations is not known a priori.'), |
|---|
| 1196 |
longDescription=_( |
|---|
| 1197 |
u"""Your string must include all three format specifiers, as is done |
|---|
| 1198 |
in this example:: |
|---|
| 1199 |
|
|---|
| 1200 |
u'Progress report: %(elapsed)s elapsed, %(opsCompleted)i operations completed, %(perOp)s per operation.' |
|---|
| 1201 |
"""), |
|---|
| 1202 |
isExposedToPythonCallers=True) |
|---|
| 1203 |
|
|---|
| 1204 |
AddPropertyMetadata(ProgressReporter.CompletionMessage, |
|---|
| 1205 |
typeMetadata=UnicodeStringTypeMetadata(), |
|---|
| 1206 |
shortDescription=_(u'printf-style format string for reporting that processing is complete.'), |
|---|
| 1207 |
longDescription=_( |
|---|
| 1208 |
u"""Your string must include all three format specifiers, as is done |
|---|
| 1209 |
in this example:: |
|---|
| 1210 |
|
|---|
| 1211 |
u'Processing complete: %(elapsed)s elapsed, %(opsCompleted)i operations completed, %(perOp)s per operation.' |
|---|
| 1212 |
"""), |
|---|
| 1213 |
isExposedToPythonCallers=True) |
|---|
| 1214 |
|
|---|
| 1215 |
AddPropertyMetadata(ProgressReporter.AbortedMessage, |
|---|
| 1216 |
typeMetadata=UnicodeStringTypeMetadata(), |
|---|
| 1217 |
shortDescription=_(u'printf-style format string for reporting that processing was stopped prematurely (i.e. that the Stop method was called before OperationsCompleted == TotalOperations).'), |
|---|
| 1218 |
longDescription=_( |
|---|
| 1219 |
u"""Your string must include all four format specifiers, as is done in |
|---|
| 1220 |
this example:: |
|---|
| 1221 |
|
|---|
| 1222 |
u'Processing stopped before all operations were completed: %(elapsed)s elapsed, %(opsCompleted)i operations completed, %(perOp)s per operation, %(opsIncomplete)i operations not completed.' |
|---|
| 1223 |
"""), |
|---|
| 1224 |
isExposedToPythonCallers=True) |
|---|
| 1225 |
|
|---|
| 1226 |
AddPropertyMetadata(ProgressReporter.LoggingChannel, |
|---|
| 1227 |
typeMetadata=UnicodeStringTypeMetadata(), |
|---|
| 1228 |
shortDescription=_(u'Logging channel that progress messages should be reported to.'), |
|---|
| 1229 |
longDescription=_( |
|---|
| 1230 |
u"""Please see the documentation for the Python logging module formore |
|---|
| 1231 |
information about logging channels. All progress messages are reported |
|---|
| 1232 |
at the Info logging level. You can configure the message filtering and |
|---|
| 1233 |
destinations by editing the GeoEco Logging.ini file."""), |
|---|
| 1234 |
isExposedToPythonCallers=True) |
|---|
| 1235 |
|
|---|
| 1236 |
AddPropertyMetadata(ProgressReporter.TotalOperations, |
|---|
| 1237 |
typeMetadata=IntegerTypeMetadata(canBeNone=True), |
|---|
| 1238 |
shortDescription=_(u'Total number of sub-operations in this long-running operation, or None if the number of sub-operations is not known a priori.'), |
|---|
| 1239 |
longDescription=_(u'This property is initialized by the Start method.'), |
|---|
| 1240 |
isExposedToPythonCallers=True) |
|---|
| 1241 |
|
|---|
| 1242 |
AddPropertyMetadata(ProgressReporter.OperationsCompleted, |
|---|
| 1243 |
typeMetadata=IntegerTypeMetadata(), |
|---|
| 1244 |
shortDescription=_(u'Total number of sub-operations that have been completed so far.'), |
|---|
| 1245 |
longDescription=_(u'This property is updated when ReportProgress is called.'), |
|---|
| 1246 |
isExposedToPythonCallers=True) |
|---|
| 1247 |
|
|---|
| 1248 |
AddPropertyMetadata(ProgressReporter.TimeStarted, |
|---|
| 1249 |
typeMetadata=ClassInstanceTypeMetadata(cls=datetime.datetime, canBeNone=True), |
|---|
| 1250 |
shortDescription=_(u'The time processing was started.'), |
|---|
| 1251 |
longDescription=_( |
|---|
| 1252 |
u"""This property is set to the current system time when Start is |
|---|
| 1253 |
called, using the datetime.datetime.now method."""), |
|---|
| 1254 |
isExposedToPythonCallers=True) |
|---|
| 1255 |
|
|---|
| 1256 |
AddPropertyMetadata(ProgressReporter.TimeCompleted, |
|---|
| 1257 |
typeMetadata=ClassInstanceTypeMetadata(cls=datetime.datetime, canBeNone=True), |
|---|
| 1258 |
shortDescription=_(u'The time processing was completed.'), |
|---|
| 1259 |
longDescription=_( |
|---|
| 1260 |
u"""This property is set to the current system time when |
|---|
| 1261 |
ReportProgress is called for the last sub-operation (when the total |
|---|
| 1262 |
number of sub-operations is known a priori) or when Stop is called |
|---|
| 1263 |
(when the the total number of sub-operations is not known a priori), |
|---|
| 1264 |
using the datetime.datetime.now method."""), |
|---|
| 1265 |
isExposedToPythonCallers=True) |
|---|
| 1266 |
|
|---|
| 1267 |
AddPropertyMetadata(ProgressReporter.HasStarted, |
|---|
| 1268 |
typeMetadata=BooleanTypeMetadata(), |
|---|
| 1269 |
shortDescription=_(u'True if processing has started (i.e. if Start was called).'), |
|---|
| 1270 |
isExposedToPythonCallers=True) |
|---|
| 1271 |
|
|---|
| 1272 |
AddPropertyMetadata(ProgressReporter.HasCompleted, |
|---|
| 1273 |
typeMetadata=BooleanTypeMetadata(), |
|---|
| 1274 |
shortDescription=_(u'True if processing has completed (i.e. the last operation was reported to ReportProgress or Stop was called).'), |
|---|
| 1275 |
isExposedToPythonCallers=True) |
|---|
| 1276 |
|
|---|
| 1277 |
AddPropertyMetadata(ProgressReporter.TimeElapsed, |
|---|
| 1278 |
typeMetadata=ClassInstanceTypeMetadata(cls=datetime.timedelta, canBeNone=True), |
|---|
| 1279 |
shortDescription=_(u'The time elapsed since processing was started, or None if processing has not started yet.'), |
|---|
| 1280 |
longDescription=_( |
|---|
| 1281 |
u"""Processing starts when Start is called and stops when |
|---|
| 1282 |
ReportProgress is called for the last sub-operation (when the total |
|---|
| 1283 |
number of sub-operations is known a priori) or when Stop is called |
|---|
| 1284 |
(when the the total number of sub-operations is not known a priori). |
|---|
| 1285 |
After processing has stopped, this property will consistently return |
|---|
| 1286 |
the total time required for processing (it will not keep increasing as |
|---|
| 1287 |
additional time passes)."""), |
|---|
| 1288 |
isExposedToPythonCallers=True) |
|---|
| 1289 |
|
|---|
| 1290 |
|
|---|
| 1291 |
|
|---|
| 1292 |
AddMethodMetadata(ProgressReporter.__init__, |
|---|
| 1293 |
shortDescription=_(u'Constructs a new %s instance.') % ProgressReporter.__name__, |
|---|
| 1294 |
isExposedToPythonCallers=True) |
|---|
| 1295 |
|
|---|
| 1296 |
AddArgumentMetadata(ProgressReporter.__init__, u'self', |
|---|
| 1297 |
typeMetadata=ClassInstanceTypeMetadata(cls=ProgressReporter), |
|---|
| 1298 |
description=_(u'%s instance.') % ProgressReporter.__name__) |
|---|
| 1299 |
|
|---|
| 1300 |
AddArgumentMetadata(ProgressReporter.__init__, u'progressMessage1', |
|---|
| 1301 |
typeMetadata=ProgressReporter.ProgressMessage1.__doc__.Obj.Type, |
|---|
| 1302 |
description=ProgressReporter.ProgressMessage1.__doc__.Obj.ShortDescription + u'\n\n' + ProgressReporter.ProgressMessage1.__doc__.Obj.LongDescription) |
|---|
| 1303 |
|
|---|
| 1304 |
AddArgumentMetadata(ProgressReporter.__init__, u'progressMessage2', |
|---|
| 1305 |
typeMetadata=ProgressReporter.ProgressMessage2.__doc__.Obj.Type, |
|---|
| 1306 |
description=ProgressReporter.ProgressMessage2.__doc__.Obj.ShortDescription + u'\n\n' + ProgressReporter.ProgressMessage2.__doc__.Obj.LongDescription) |
|---|
| 1307 |
|
|---|
| 1308 |
AddArgumentMetadata(ProgressReporter.__init__, u'completionMessage', |
|---|
| 1309 |
typeMetadata=ProgressReporter.CompletionMessage.__doc__.Obj.Type, |
|---|
| 1310 |
description=ProgressReporter.CompletionMessage.__doc__.Obj.ShortDescription + u'\n\n' + ProgressReporter.CompletionMessage.__doc__.Obj.LongDescription) |
|---|
| 1311 |
|
|---|
| 1312 |
AddArgumentMetadata(ProgressReporter.__init__, u'abortedMessage', |
|---|
| 1313 |
typeMetadata=ProgressReporter.AbortedMessage.__doc__.Obj.Type, |
|---|
| 1314 |
description=ProgressReporter.AbortedMessage.__doc__.Obj.ShortDescription + u'\n\n' + ProgressReporter.AbortedMessage.__doc__.Obj.LongDescription) |
|---|
| 1315 |
|
|---|
| 1316 |
AddArgumentMetadata(ProgressReporter.__init__, u'loggingChannel', |
|---|
| 1317 |
typeMetadata=ProgressReporter.LoggingChannel.__doc__.Obj.Type, |
|---|
| 1318 |
description=ProgressReporter.LoggingChannel.__doc__.Obj.ShortDescription + u'\n\n' + ProgressReporter.LoggingChannel.__doc__.Obj.LongDescription) |
|---|
| 1319 |
|
|---|
| 1320 |
AddResultMetadata(ProgressReporter.__init__, u'progressReporter', |
|---|
| 1321 |
typeMetadata=ClassInstanceTypeMetadata(cls=ProgressReporter), |
|---|
| 1322 |
description=_(u'New %s instance.') % ProgressReporter.__name__) |
|---|
| 1323 |
|
|---|
| 1324 |
|
|---|
| 1325 |
|
|---|
| 1326 |
AddMethodMetadata(ProgressReporter.Start, |
|---|
| 1327 |
shortDescription=_(u'Signals the ProgressReporter that processing has started.'), |
|---|
| 1328 |
isExposedToPythonCallers=True) |
|---|
| 1329 |
|
|---|
| 1330 |
CopyArgumentMetadata(ProgressReporter.__init__, u'self', ProgressReporter.Start, u'self') |
|---|
| 1331 |
|
|---|
| 1332 |
AddArgumentMetadata(ProgressReporter.Start, u'totalOperations', |
|---|
| 1333 |
typeMetadata=IntegerTypeMetadata(canBeNone=True, minValue=1), |
|---|
| 1334 |
description=_(u'Total number of sub-operations that will be performed, or None if the number of sub-operations is not known.')) |
|---|
| 1335 |
|
|---|
| 1336 |
|
|---|
| 1337 |
|
|---|
| 1338 |
AddMethodMetadata(ProgressReporter.ReportProgress, |
|---|
| 1339 |
shortDescription=_(u'Signals the ProgressReporter that another one or more sub-operations just completed.'), |
|---|
| 1340 |
longDescription=_( |
|---|
| 1341 |
u"""This method will periodically report progress messages as |
|---|
| 1342 |
described in the class-level documentation. You must call Start before |
|---|
| 1343 |
calling this method."""), |
|---|
| 1344 |
isExposedToPythonCallers=True) |
|---|
| 1345 |
|
|---|
| 1346 |
CopyArgumentMetadata(ProgressReporter.__init__, u'self', ProgressReporter.ReportProgress, u'self') |
|---|
| 1347 |
|
|---|
| 1348 |
AddArgumentMetadata(ProgressReporter.ReportProgress, u'operationsCompleted', |
|---|
| 1349 |
typeMetadata=IntegerTypeMetadata(minValue=1), |
|---|
| 1350 |
description=_( |
|---|
| 1351 |
u"""Total number of sub-operations that just completed, typically 1. |
|---|
| 1352 |
You should provide the number of sub-operations that have completed |
|---|
| 1353 |
since you last called this method. Do not pass in a cumulative total.""")) |
|---|
| 1354 |
|
|---|
| 1355 |
|
|---|
| 1356 |
|
|---|
| 1357 |
AddMethodMetadata(ProgressReporter.Stop, |
|---|
| 1358 |
shortDescription=_(u'Signals the ProgressReporter that processing is complete.'), |
|---|
| 1359 |
longDescription=_( |
|---|
| 1360 |
u"""This method will report a completion message as described in the |
|---|
| 1361 |
class-level documentation. You must call Start before calling this |
|---|
| 1362 |
method. If provided a value for totalOperations when you called Start, |
|---|
| 1363 |
and the number of completed operations has not reached this total, |
|---|
| 1364 |
Stop will report AbortedMessage."""), |
|---|
| 1365 |
isExposedToPythonCallers=True) |
|---|
| 1366 |
|
|---|
| 1367 |
CopyArgumentMetadata(ProgressReporter.__init__, u'self', ProgressReporter.Stop, u'self') |
|---|
| 1368 |
|
|---|
| 1369 |
|
|---|
| 1370 |
|
|---|
| 1371 |
|
|---|
| 1372 |
|
|---|
| 1373 |
|
|---|
| 1374 |
__all__ = ['Logger'] |
|---|