|
Lines 53-58
Link Here
|
| 53 |
""" |
53 |
""" |
| 54 |
|
54 |
|
| 55 |
import inspect |
55 |
import inspect |
|
|
56 |
from threading import Thread |
| 56 |
|
57 |
|
| 57 |
from univention.lib.i18n import Translation |
58 |
from univention.lib.i18n import Translation |
| 58 |
_ = Translation( 'univention.management.console' ).translate |
59 |
_ = Translation( 'univention.management.console' ).translate |
|
Lines 258-269
Link Here
|
| 258 |
if function is None: |
259 |
if function is None: |
| 259 |
return lambda f: simple_response(f, with_flavor) |
260 |
return lambda f: simple_response(f, with_flavor) |
| 260 |
|
261 |
|
|
|
262 |
# does it |
| 263 |
# return value ? |
| 264 |
# => just send the value to the frontend |
| 265 |
# or |
| 266 |
# yield value ? |
| 267 |
# => send the value to the frontend and |
| 268 |
# finish the function in a thread |
| 269 |
function_yields = inspect.isgeneratorfunction(function) |
| 270 |
|
| 261 |
# fake a generator function that yields whatever the original |
271 |
# fake a generator function that yields whatever the original |
| 262 |
# function returned |
272 |
# function returned |
| 263 |
def _fake_func(self, iterator, *args): |
273 |
def _fake_func(self, iterator, *args): |
| 264 |
for args in iterator: |
274 |
for args in iterator: |
| 265 |
break |
275 |
break |
| 266 |
yield function(self, *args) |
276 |
if function_yields: |
|
|
277 |
for res in function(self, *args): |
| 278 |
yield res |
| 279 |
else: |
| 280 |
res = function(self, *args) |
| 281 |
yield res |
| 267 |
copy_function_meta_data(function, _fake_func, copy_arg_inspect=True) |
282 |
copy_function_meta_data(function, _fake_func, copy_arg_inspect=True) |
| 268 |
# fake another variable name |
283 |
# fake another variable name |
| 269 |
# the name is not important as it is removed from the list while |
284 |
# the name is not important as it is removed from the list while |
|
Lines 279-286
Link Here
|
| 279 |
|
294 |
|
| 280 |
# fake a multi_request |
295 |
# fake a multi_request |
| 281 |
request.options = [request.options] |
296 |
request.options = [request.options] |
| 282 |
result = _multi_response(self, request) |
297 |
gen = _multi_response(self, request) |
| 283 |
self.finished(request.id, result[0]) |
298 |
result = gen.next() |
|
|
299 |
self.finished(request.id, result) |
| 300 |
if function_yields: |
| 301 |
def _run_to_end(local_gen): |
| 302 |
for result in local_gen: |
| 303 |
pass |
| 304 |
thread = Thread(target=_run_to_end, args=[gen]) |
| 305 |
thread.start() |
| 284 |
|
306 |
|
| 285 |
copy_function_meta_data(function, _response) |
307 |
copy_function_meta_data(function, _response) |
| 286 |
return _response |
308 |
return _response |
|
Lines 329-335
Link Here
|
| 329 |
return lambda f: multi_response(f, with_flavor, single_values) |
351 |
return lambda f: multi_response(f, with_flavor, single_values) |
| 330 |
response_func = _eval_simple_decorated_function(function, with_flavor, single_values) |
352 |
response_func = _eval_simple_decorated_function(function, with_flavor, single_values) |
| 331 |
def _response(self, request): |
353 |
def _response(self, request): |
| 332 |
result = response_func(self, request) |
354 |
result = list(response_func(self, request)) |
| 333 |
self.finished(request.id, result) |
355 |
self.finished(request.id, result) |
| 334 |
copy_function_meta_data(function, _response) |
356 |
copy_function_meta_data(function, _response) |
| 335 |
return _response |
357 |
return _response |
|
Lines 375-390
Link Here
|
| 375 |
# check for required arguments (those without default) |
397 |
# check for required arguments (those without default) |
| 376 |
raise UMC_OptionMissing(arg) |
398 |
raise UMC_OptionMissing(arg) |
| 377 |
|
399 |
|
| 378 |
|
|
|
| 379 |
# checked for required arguments, set default... now run! |
400 |
# checked for required arguments, set default... now run! |
| 380 |
result = [] |
|
|
| 381 |
|
| 382 |
iterator = RequestOptionsIterator(request.options, arguments, single_values) |
401 |
iterator = RequestOptionsIterator(request.options, arguments, single_values) |
| 383 |
nones = [None] * len(arguments) |
402 |
nones = [None] * len(arguments) |
| 384 |
for res in function(self, iterator, *nones): |
403 |
return function(self, iterator, *nones) |
| 385 |
result.append(res) |
|
|
| 386 |
|
| 387 |
return result |
| 388 |
return _response |
404 |
return _response |
| 389 |
|
405 |
|
| 390 |
class RequestOptionsIterator(object): |
406 |
class RequestOptionsIterator(object): |
|
Lines 439-469
Link Here
|
| 439 |
# copy __module__, otherwise it would be "univention.management.console.modules.decorators" |
455 |
# copy __module__, otherwise it would be "univention.management.console.modules.decorators" |
| 440 |
new_function.__module__ = original_function.__module__ |
456 |
new_function.__module__ = original_function.__module__ |
| 441 |
|
457 |
|
| 442 |
def log(function=None, sensitives=None, customs=None, single_values=False): |
458 |
def log(function=None, sensitives=None, customs=None, single_values=False, logger=None, simple_threaded=False): |
| 443 |
'''Log decorator to be used with |
459 |
'''Log decorator to be used with :func:`simple_response`. |
| 444 |
:func:`simple_response`:: |
|
|
| 445 |
|
460 |
|
|
|
461 |
You can specify any function to handle the log information. By default |
| 462 |
it is handled by MODULE.info, but you can pass MODULE.process (already |
| 463 |
logs when *umc/module/debug/level* is set to 2) as well as any other |
| 464 |
function that can handle strings:: |
| 465 |
|
| 446 |
@simple_response |
466 |
@simple_response |
| 447 |
@log |
467 |
@log |
| 448 |
def my_func(self, var1, var2): |
468 |
def my_func(self, var1, var2): |
| 449 |
return "%s__%s" % (var1, var2) |
469 |
return "%s__%s" % (var1, var2) |
| 450 |
|
470 |
|
| 451 |
The above example will write two lines into the logfile for the |
471 |
The above example will write two lines into the logfile for the module |
| 452 |
module (given that the the UCR variable *umc/module/debug/level* |
472 |
(given that the the UCR variable *umc/module/debug/level* is set to at |
| 453 |
is set to at least 3):: |
473 |
least 3):: |
| 454 |
|
474 |
|
| 455 |
<date> MODULE ( INFO ) : my_func got: var1='value1', var2='value2' |
475 |
<date> MODULE ( INFO ) : my_func got: var1='value1', var2='value2' |
| 456 |
<date> MODULE ( INFO ) : my_func returned: 'value1__value2' |
476 |
<date> MODULE ( INFO ) : my_func returned: 'value1__value2' |
| 457 |
|
477 |
|
| 458 |
The variable names are ordered by appearance and hold the values that |
478 |
The variable names are ordered by appearance and hold the values that |
| 459 |
are actually going to be passed to the function (i.e. after they were |
479 |
are actually going to be passed to the function (i.e. after they were |
| 460 |
:func:`sanitize` 'd or set to their default value). |
480 |
:func:`sanitize` 'd or set to their default value). You may specify the |
| 461 |
You may specify the names of sensitive arguments that should not |
481 |
names of sensitive arguments that should not show up in log files and |
| 462 |
show up in log files and custom functions that can alter the |
482 |
custom functions that can alter the representation of a certain |
| 463 |
representation of a certain variable's values (useful for non-standard |
483 |
variable's values (useful for non-standard datatypes like regular |
| 464 |
datatypes like regular expressions - you may have used a |
484 |
expressions - you may have used a |
| 465 |
:class:`~univention.management.console.modules.sanitizers.PatternSanitizer` |
485 |
:class:`~univention.management.console.modules.sanitizers.PatternSanitizer`):: |
| 466 |
):: |
|
|
| 467 |
|
486 |
|
| 468 |
@sanitize(pattern=PatternSanitizer()) |
487 |
@sanitize(pattern=PatternSanitizer()) |
| 469 |
@simple_reponse |
488 |
@simple_reponse |
|
Lines 479-501
Link Here
|
| 479 |
The decorator also works with :func:`multi_response`:: |
498 |
The decorator also works with :func:`multi_response`:: |
| 480 |
|
499 |
|
| 481 |
@multi_response |
500 |
@multi_response |
| 482 |
@log |
501 |
@log(logger=MODULE.process) # logs to PROCESS, not INFO |
| 483 |
def multi_my_func(self, var1, var2): |
502 |
def multi_my_func(self, var1, var2): |
| 484 |
return "%s__%s" % (var1, var2) |
503 |
return "%s__%s" % (var1, var2) |
| 485 |
|
504 |
|
| 486 |
This results in something like:: |
505 |
This results in something like:: |
| 487 |
|
506 |
|
| 488 |
<date> MODULE ( INFO ) : multi_my_func got: [var1='value1', var2='value2'], [var1='value3', var2='value4'] |
507 |
<date> MODULE ( PROCESS ) : multi_my_func got: [var1='value1', var2='value2'], [var1='value3', var2='value4'] |
| 489 |
<date> MODULE ( INFO ) : multi_my_func returned: ['value1__value2', 'value3__value4'] |
508 |
<date> MODULE ( PROCESS ) : multi_my_func returned: ['value1__value2', 'value3__value4'] |
| 490 |
''' |
509 |
''' |
| 491 |
if function is None: |
510 |
if function is None: |
| 492 |
return lambda f: log(f, sensitives, customs, single_values) |
511 |
return lambda f: log(f, sensitives, customs, single_values, logger, simple_threaded) |
| 493 |
if customs is None: |
512 |
if customs is None: |
| 494 |
customs = {} |
513 |
customs = {} |
| 495 |
if sensitives is None: |
514 |
if sensitives is None: |
| 496 |
sensitives = [] |
515 |
sensitives = [] |
| 497 |
for sensitive in sensitives: |
516 |
for sensitive in sensitives: |
| 498 |
customs[sensitive] = lambda x: '********' |
517 |
customs[sensitive] = lambda x: '********' |
|
|
518 |
if logger is None: |
| 519 |
logger = MODULE.info |
| 499 |
|
520 |
|
| 500 |
def _log(names, args): |
521 |
def _log(names, args): |
| 501 |
if single_values: |
522 |
if single_values: |
|
Lines 507-537
Link Here
|
| 507 |
name = function.__name__ |
528 |
name = function.__name__ |
| 508 |
# multi_response yields i.e. is generator function |
529 |
# multi_response yields i.e. is generator function |
| 509 |
if inspect.isgeneratorfunction(function): |
530 |
if inspect.isgeneratorfunction(function): |
| 510 |
# remove self, iterator |
531 |
# problem: simple_response can also yield |
| 511 |
names = names[2:] |
532 |
if simple_threaded: |
| 512 |
def _response(self, iterator, *args): |
533 |
# remove self |
| 513 |
arg_reprs = [] |
534 |
names = names[1:] |
| 514 |
for element in iterator: |
535 |
def _response_simple_threaded(self, *args): |
| 515 |
arg_repr = _log(names, element) |
536 |
arg_repr = _log(names, args) |
| 516 |
if arg_repr: |
537 |
if arg_repr: |
| 517 |
arg_reprs.append(arg_repr) |
538 |
logger('%s got: %s' % (name, ', '.join(arg_repr))) |
| 518 |
if arg_reprs: |
539 |
result = function(self, *args) |
| 519 |
MODULE.info('%s got: [%s]' % (name, '], ['.join(', '.join(arg_repr) for arg_repr in arg_reprs))) |
540 |
res = result.next() |
| 520 |
result = [] |
541 |
logger('%s returned: %r' % (name, res)) |
| 521 |
for res in function(self, iterator, *args): |
|
|
| 522 |
result.append(res) |
| 523 |
yield res |
542 |
yield res |
| 524 |
MODULE.info('%s returned: %r' % (name, result)) |
543 |
for res in result: |
|
|
544 |
yield res |
| 545 |
_response = _response_simple_threaded |
| 546 |
else: |
| 547 |
# remove self, iterator |
| 548 |
names = names[2:] |
| 549 |
def _response_multiple(self, iterator, *args): |
| 550 |
arg_reprs = [] |
| 551 |
for element in iterator: |
| 552 |
arg_repr = _log(names, element) |
| 553 |
if arg_repr: |
| 554 |
arg_reprs.append(arg_repr) |
| 555 |
if arg_reprs: |
| 556 |
logger('%s got: [%s]' % (name, '], ['.join(', '.join(arg_repr) for arg_repr in arg_reprs))) |
| 557 |
result = [] |
| 558 |
for res in function(self, iterator, *args): |
| 559 |
result.append(res) |
| 560 |
yield res |
| 561 |
logger('%s returned: %r' % (name, result)) |
| 562 |
_response = _response_multiple |
| 525 |
else: |
563 |
else: |
| 526 |
# remove self |
564 |
# remove self |
| 527 |
names = names[1:] |
565 |
names = names[1:] |
| 528 |
def _response(self, *args): |
566 |
def _response_simple(self, *args): |
| 529 |
arg_repr = _log(names, args) |
567 |
arg_repr = _log(names, args) |
| 530 |
if arg_repr: |
568 |
if arg_repr: |
| 531 |
MODULE.info('%s got: %s' % (name, ', '.join(arg_repr))) |
569 |
logger('%s got: %s' % (name, ', '.join(arg_repr))) |
| 532 |
result = function(self, *args) |
570 |
result = function(self, *args) |
| 533 |
MODULE.info('%s returned: %r' % (name, result)) |
571 |
logger('%s returned: %r' % (name, result)) |
| 534 |
return result |
572 |
return result |
|
|
573 |
_response = _response_simple |
| 535 |
copy_function_meta_data(function, _response, copy_arg_inspect=True) |
574 |
copy_function_meta_data(function, _response, copy_arg_inspect=True) |
| 536 |
return _response |
575 |
return _response |
| 537 |
|
576 |
|