1# vim:fileencoding=utf-8:noet 2from __future__ import (unicode_literals, division, absolute_import, print_function) 3 4import os 5import re 6import logging 7 8from collections import defaultdict 9 10from powerline.lib.threaded import ThreadedSegment 11from powerline.lib.unicode import unicode 12from powerline.lint.markedjson.markedvalue import MarkedUnicode 13from powerline.lint.markedjson.error import DelayedEchoErr, Mark 14from powerline.lint.selfcheck import havemarks 15from powerline.lint.context import JStr, list_themes 16from powerline.lint.imp import WithPath, import_function, import_segment 17from powerline.lint.spec import Spec 18from powerline.lint.inspect import getconfigargspec 19 20 21list_sep = JStr(', ') 22 23 24generic_keys = set(( 25 'exclude_modes', 'include_modes', 26 'exclude_function', 'include_function', 27 'width', 'align', 28 'name', 29 'draw_soft_divider', 'draw_hard_divider', 30 'priority', 31 'after', 'before', 32 'display' 33)) 34type_keys = { 35 'function': set(('function', 'args', 'draw_inner_divider')), 36 'string': set(('contents', 'type', 'highlight_groups', 'divider_highlight_group')), 37 'segment_list': set(('function', 'segments', 'args', 'type')), 38} 39required_keys = { 40 'function': set(('function',)), 41 'string': set(()), 42 'segment_list': set(('function', 'segments',)), 43} 44highlight_keys = set(('highlight_groups', 'name')) 45 46 47def get_function_strings(function_name, context, ext): 48 if '.' in function_name: 49 module, function_name = function_name.rpartition('.')[::2] 50 else: 51 module = context[0][1].get( 52 'default_module', MarkedUnicode('powerline.segments.' + ext, None)) 53 return module, function_name 54 55 56def check_matcher_func(ext, match_name, data, context, echoerr): 57 havemarks(match_name) 58 import_paths = [os.path.expanduser(path) for path in context[0][1].get('common', {}).get('paths', [])] 59 60 match_module, separator, match_function = match_name.rpartition('.') 61 if not separator: 62 match_module = 'powerline.matchers.{0}'.format(ext) 63 match_function = match_name 64 with WithPath(import_paths): 65 try: 66 func = getattr(__import__(str(match_module), fromlist=[str(match_function)]), str(match_function)) 67 except ImportError: 68 echoerr(context='Error while loading matcher functions', 69 problem='failed to load module {0}'.format(match_module), 70 problem_mark=match_name.mark) 71 return True, False, True 72 except AttributeError: 73 echoerr(context='Error while loading matcher functions', 74 problem='failed to load matcher function {0}'.format(match_function), 75 problem_mark=match_name.mark) 76 return True, False, True 77 78 if not callable(func): 79 echoerr(context='Error while loading matcher functions', 80 problem='loaded “function” {0} is not callable'.format(match_function), 81 problem_mark=match_name.mark) 82 return True, False, True 83 84 if hasattr(func, 'func_code') and hasattr(func.func_code, 'co_argcount'): 85 if func.func_code.co_argcount != 1: 86 echoerr( 87 context='Error while loading matcher functions', 88 problem=( 89 'function {0} accepts {1} arguments instead of 1. ' 90 'Are you sure it is the proper function?' 91 ).format(match_function, func.func_code.co_argcount), 92 problem_mark=match_name.mark 93 ) 94 95 return True, False, False 96 97 98def check_ext(ext, data, context, echoerr): 99 havemarks(ext) 100 hadsomedirs = False 101 hadproblem = False 102 if ext not in data['lists']['exts']: 103 hadproblem = True 104 echoerr(context='Error while loading {0} extension configuration'.format(ext), 105 context_mark=ext.mark, 106 problem='extension configuration does not exist') 107 else: 108 for typ in ('themes', 'colorschemes'): 109 if ext not in data['configs'][typ] and not data['configs']['top_' + typ]: 110 hadproblem = True 111 echoerr(context='Error while loading {0} extension configuration'.format(ext), 112 context_mark=ext.mark, 113 problem='{0} configuration does not exist'.format(typ)) 114 else: 115 hadsomedirs = True 116 return hadsomedirs, hadproblem 117 118 119def check_config(d, theme, data, context, echoerr): 120 if len(context) == 4: 121 ext = context[-2][0] 122 else: 123 # local_themes 124 ext = context[-3][0] 125 if ext not in data['lists']['exts']: 126 echoerr(context='Error while loading {0} extension configuration'.format(ext), 127 context_mark=ext.mark, 128 problem='extension configuration does not exist') 129 return True, False, True 130 if ( 131 (ext not in data['configs'][d] or theme not in data['configs'][d][ext]) 132 and theme not in data['configs']['top_' + d] 133 ): 134 echoerr(context='Error while loading {0} from {1} extension configuration'.format(d[:-1], ext), 135 problem='failed to find configuration file {0}/{1}/{2}.json'.format(d, ext, theme), 136 problem_mark=theme.mark) 137 return True, False, True 138 return True, False, False 139 140 141def check_top_theme(theme, data, context, echoerr): 142 havemarks(theme) 143 if theme not in data['configs']['top_themes']: 144 echoerr(context='Error while checking extension configuration (key {key})'.format(key=context.key), 145 context_mark=context[-2][0].mark, 146 problem='failed to find top theme {0}'.format(theme), 147 problem_mark=theme.mark) 148 return True, False, True 149 return True, False, False 150 151 152def check_color(color, data, context, echoerr): 153 havemarks(color) 154 if (color not in data['colors_config'].get('colors', {}) 155 and color not in data['colors_config'].get('gradients', {})): 156 echoerr( 157 context='Error while checking highlight group in colorscheme (key {key})'.format( 158 key=context.key), 159 problem='found unexistent color or gradient {0}'.format(color), 160 problem_mark=color.mark 161 ) 162 return True, False, True 163 return True, False, False 164 165 166def check_translated_group_name(group, data, context, echoerr): 167 return check_group(group, data, context, echoerr) 168 169 170def check_group(group, data, context, echoerr): 171 havemarks(group) 172 if not isinstance(group, unicode): 173 return True, False, False 174 colorscheme = data['colorscheme'] 175 ext = data['ext'] 176 configs = None 177 if ext: 178 def listed_key(d, k): 179 try: 180 return [d[k]] 181 except KeyError: 182 return [] 183 184 if colorscheme == '__main__': 185 colorscheme_names = set(data['ext_colorscheme_configs'][ext]) 186 colorscheme_names.update(data['top_colorscheme_configs']) 187 colorscheme_names.discard('__main__') 188 configs = [ 189 ( 190 name, 191 listed_key(data['ext_colorscheme_configs'][ext], name) 192 + listed_key(data['ext_colorscheme_configs'][ext], '__main__') 193 + listed_key(data['top_colorscheme_configs'], name) 194 ) 195 for name in colorscheme_names 196 ] 197 else: 198 configs = [ 199 ( 200 colorscheme, 201 listed_key(data['ext_colorscheme_configs'][ext], colorscheme) 202 + listed_key(data['ext_colorscheme_configs'][ext], '__main__') 203 + listed_key(data['top_colorscheme_configs'], colorscheme) 204 ) 205 ] 206 else: 207 try: 208 configs = [(colorscheme, [data['top_colorscheme_configs'][colorscheme]])] 209 except KeyError: 210 pass 211 hadproblem = False 212 for new_colorscheme, config_lst in configs: 213 not_found = [] 214 new_data = data.copy() 215 new_data['colorscheme'] = new_colorscheme 216 for config in config_lst: 217 havemarks(config) 218 try: 219 group_data = config['groups'][group] 220 except KeyError: 221 not_found.append(config.mark.name) 222 else: 223 proceed, echo, chadproblem = check_group( 224 group_data, 225 new_data, 226 context, 227 echoerr, 228 ) 229 if chadproblem: 230 hadproblem = True 231 if not proceed: 232 break 233 if not_found and len(not_found) == len(config_lst): 234 echoerr( 235 context='Error while checking group definition in colorscheme (key {key})'.format( 236 key=context.key), 237 problem='name {0} is not present anywhere in {1} {2} {3} colorschemes: {4}'.format( 238 group, len(not_found), ext, new_colorscheme, ', '.join(not_found)), 239 problem_mark=group.mark 240 ) 241 hadproblem = True 242 return True, False, hadproblem 243 244 245def check_key_compatibility(segment, data, context, echoerr): 246 havemarks(segment) 247 segment_type = segment.get('type', MarkedUnicode('function', None)) 248 havemarks(segment_type) 249 250 if segment_type not in type_keys: 251 echoerr(context='Error while checking segments (key {key})'.format(key=context.key), 252 problem='found segment with unknown type {0}'.format(segment_type), 253 problem_mark=segment_type.mark) 254 return False, False, True 255 256 hadproblem = False 257 258 keys = set(segment) 259 if not ((keys - generic_keys) < type_keys[segment_type]): 260 unknown_keys = keys - generic_keys - type_keys[segment_type] 261 echoerr( 262 context='Error while checking segments (key {key})'.format(key=context.key), 263 context_mark=context[-1][1].mark, 264 problem='found keys not used with the current segment type: {0}'.format( 265 list_sep.join(unknown_keys)), 266 problem_mark=list(unknown_keys)[0].mark 267 ) 268 hadproblem = True 269 270 if not (keys >= required_keys[segment_type]): 271 missing_keys = required_keys[segment_type] - keys 272 echoerr( 273 context='Error while checking segments (key {key})'.format(key=context.key), 274 context_mark=context[-1][1].mark, 275 problem='found missing required keys: {0}'.format( 276 list_sep.join(missing_keys)) 277 ) 278 hadproblem = True 279 280 if not (segment_type == 'function' or (keys & highlight_keys)): 281 echoerr( 282 context='Error while checking segments (key {key})'.format(key=context.key), 283 context_mark=context[-1][1].mark, 284 problem=( 285 'found missing keys required to determine highlight group. ' 286 'Either highlight_groups or name key must be present' 287 ) 288 ) 289 hadproblem = True 290 291 return True, False, hadproblem 292 293 294def check_segment_module(module, data, context, echoerr): 295 havemarks(module) 296 with WithPath(data['import_paths']): 297 try: 298 __import__(str(module)) 299 except ImportError as e: 300 if echoerr.logger.level >= logging.DEBUG: 301 echoerr.logger.exception(e) 302 echoerr(context='Error while checking segments (key {key})'.format(key=context.key), 303 problem='failed to import module {0}'.format(module), 304 problem_mark=module.mark) 305 return True, False, True 306 return True, False, False 307 308 309def check_full_segment_data(segment, data, context, echoerr): 310 if 'name' not in segment and 'function' not in segment: 311 return True, False, False 312 313 ext = data['ext'] 314 theme_segment_data = context[0][1].get('segment_data', {}) 315 main_theme_name = data['main_config'].get('ext', {}).get(ext, {}).get('theme', None) 316 if not main_theme_name or data['theme'] == main_theme_name: 317 top_segment_data = {} 318 else: 319 top_segment_data = data['ext_theme_configs'].get(main_theme_name, {}).get('segment_data', {}) 320 321 if segment.get('type', 'function') == 'function': 322 function_name = segment.get('function') 323 if function_name: 324 module, function_name = get_function_strings(function_name, context, ext) 325 names = [module + '.' + function_name, function_name] 326 else: 327 names = [] 328 elif segment.get('name'): 329 names = [segment['name']] 330 else: 331 return True, False, False 332 333 segment_copy = segment.copy() 334 335 for key in ('before', 'after', 'args', 'contents'): 336 if key not in segment_copy: 337 for segment_data in [theme_segment_data, top_segment_data]: 338 for name in names: 339 try: 340 val = segment_data[name][key] 341 k = segment_data[name].keydict[key] 342 segment_copy[k] = val 343 except KeyError: 344 pass 345 346 return check_key_compatibility(segment_copy, data, context, echoerr) 347 348 349highlight_group_spec = Spec().ident().copy 350_highlight_group_spec = highlight_group_spec().context_message( 351 'Error while checking function documentation while checking theme (key {key})') 352 353 354def check_hl_group_name(hl_group, context_mark, context, echoerr): 355 '''Check highlight group name: it should match naming conventions 356 357 :param str hl_group: 358 Checked group. 359 :param Mark context_mark: 360 Context mark. May be ``None``. 361 :param Context context: 362 Current context. 363 :param func echoerr: 364 Function used for error reporting. 365 366 :return: ``False`` if check succeeded and ``True`` if it failed. 367 ''' 368 return _highlight_group_spec.match(hl_group, context_mark=context_mark, context=context, echoerr=echoerr)[1] 369 370 371def check_segment_function(function_name, data, context, echoerr): 372 havemarks(function_name) 373 ext = data['ext'] 374 module, function_name = get_function_strings(function_name, context, ext) 375 if context[-2][1].get('type', 'function') == 'function': 376 func = import_segment(function_name, data, context, echoerr, module=module) 377 378 if not func: 379 return True, False, True 380 381 hl_groups = [] 382 divider_hl_group = None 383 384 hadproblem = False 385 386 if func.__doc__: 387 NO_H_G_USED_STR = 'No highlight groups are used (literal segment).' 388 H_G_USED_STR = 'Highlight groups used: ' 389 LHGUS = len(H_G_USED_STR) 390 D_H_G_USED_STR = 'Divider highlight group used: ' 391 LDHGUS = len(D_H_G_USED_STR) 392 pointer = 0 393 mark_name = '<{0} docstring>'.format(function_name) 394 for i, line in enumerate(func.__doc__.split('\n')): 395 if H_G_USED_STR in line: 396 idx = line.index(H_G_USED_STR) + LHGUS 397 if hl_groups is None: 398 idx -= LHGUS 399 mark = Mark(mark_name, i + 1, idx + 1, func.__doc__, pointer + idx) 400 echoerr( 401 context='Error while checking theme (key {key})'.format(key=context.key), 402 context_mark=function_name.mark, 403 problem=( 404 'found highlight group definition in addition to sentence stating that ' 405 'no highlight groups are used' 406 ), 407 problem_mark=mark, 408 ) 409 hadproblem = True 410 continue 411 hl_groups.append(( 412 line[idx:], 413 (mark_name, i + 1, idx + 1, func.__doc__), 414 pointer + idx 415 )) 416 elif D_H_G_USED_STR in line: 417 idx = line.index(D_H_G_USED_STR) + LDHGUS + 2 418 mark = Mark(mark_name, i + 1, idx + 1, func.__doc__, pointer + idx) 419 divider_hl_group = MarkedUnicode(line[idx:-3], mark) 420 elif NO_H_G_USED_STR in line: 421 idx = line.index(NO_H_G_USED_STR) 422 if hl_groups: 423 mark = Mark(mark_name, i + 1, idx + 1, func.__doc__, pointer + idx) 424 echoerr( 425 context='Error while checking theme (key {key})'.format(key=context.key), 426 context_mark=function_name.mark, 427 problem=( 428 'found sentence stating that no highlight groups are used ' 429 'in addition to highlight group definition' 430 ), 431 problem_mark=mark, 432 ) 433 hadproblem = True 434 continue 435 hl_groups = None 436 pointer += len(line) + len('\n') 437 438 if divider_hl_group: 439 r = hl_exists(divider_hl_group, data, context, echoerr, allow_gradients=True) 440 if r: 441 echoerr( 442 context='Error while checking theme (key {key})'.format(key=context.key), 443 context_mark=function_name.mark, 444 problem=( 445 'found highlight group {0} not defined in the following colorschemes: {1}\n' 446 '(Group name was obtained from function documentation.)' 447 ).format(divider_hl_group, list_sep.join(r)), 448 problem_mark=divider_hl_group.mark, 449 ) 450 hadproblem = True 451 if check_hl_group_name(divider_hl_group, function_name.mark, context, echoerr): 452 hadproblem = True 453 454 if hl_groups: 455 greg = re.compile(r'``([^`]+)``( \(gradient\))?') 456 parsed_hl_groups = [] 457 for line, mark_args, pointer in hl_groups: 458 for s in line.split(', '): 459 required_pack = [] 460 sub_pointer = pointer 461 for subs in s.split(' or '): 462 match = greg.match(subs) 463 try: 464 if not match: 465 continue 466 hl_group = MarkedUnicode( 467 match.group(1), 468 Mark(*mark_args, pointer=sub_pointer + match.start(1)) 469 ) 470 if check_hl_group_name(hl_group, function_name.mark, context, echoerr): 471 hadproblem = True 472 gradient = bool(match.group(2)) 473 required_pack.append((hl_group, gradient)) 474 finally: 475 sub_pointer += len(subs) + len(' or ') 476 parsed_hl_groups.append(required_pack) 477 pointer += len(s) + len(', ') 478 del hl_group, gradient 479 for required_pack in parsed_hl_groups: 480 rs = [ 481 hl_exists(hl_group, data, context, echoerr, allow_gradients=('force' if gradient else False)) 482 for hl_group, gradient in required_pack 483 ] 484 if all(rs): 485 echoerr( 486 context='Error while checking theme (key {key})'.format(key=context.key), 487 problem=( 488 'found highlight groups list ({0}) with all groups not defined in some colorschemes\n' 489 '(Group names were taken from function documentation.)' 490 ).format(list_sep.join((h[0] for h in required_pack))), 491 problem_mark=function_name.mark 492 ) 493 for r, h in zip(rs, required_pack): 494 echoerr( 495 context='Error while checking theme (key {key})'.format(key=context.key), 496 problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( 497 h[0], list_sep.join(r)) 498 ) 499 hadproblem = True 500 elif hl_groups is not None: 501 r = hl_exists(function_name, data, context, echoerr, allow_gradients=True) 502 if r: 503 echoerr( 504 context='Error while checking theme (key {key})'.format(key=context.key), 505 problem=( 506 'found highlight group {0} not defined in the following colorschemes: {1}\n' 507 '(If not specified otherwise in documentation, ' 508 'highlight group for function segments\n' 509 'is the same as the function name.)' 510 ).format(function_name, list_sep.join(r)), 511 problem_mark=function_name.mark 512 ) 513 hadproblem = True 514 515 return True, False, hadproblem 516 elif context[-2][1].get('type') != 'segment_list': 517 if function_name not in context[0][1].get('segment_data', {}): 518 main_theme_name = data['main_config'].get('ext', {}).get(ext, {}).get('theme', None) 519 if data['theme'] == main_theme_name: 520 main_theme = {} 521 else: 522 main_theme = data['ext_theme_configs'].get(main_theme_name, {}) 523 if ( 524 function_name not in main_theme.get('segment_data', {}) 525 and function_name not in data['ext_theme_configs'].get('__main__', {}).get('segment_data', {}) 526 and not any(((function_name in theme.get('segment_data', {})) for theme in data['top_themes'].values())) 527 ): 528 echoerr(context='Error while checking segments (key {key})'.format(key=context.key), 529 problem='found useless use of name key (such name is not present in theme/segment_data)', 530 problem_mark=function_name.mark) 531 532 return True, False, False 533 534 535def hl_group_in_colorscheme(hl_group, cconfig, allow_gradients, data, context, echoerr): 536 havemarks(hl_group, cconfig) 537 if hl_group not in cconfig.get('groups', {}): 538 return False 539 elif not allow_gradients or allow_gradients == 'force': 540 group_config = cconfig['groups'][hl_group] 541 while isinstance(group_config, unicode): 542 try: 543 group_config = cconfig['groups'][group_config] 544 except KeyError: 545 # No such group. Error was already reported when checking 546 # colorschemes. 547 return True 548 havemarks(group_config) 549 hadgradient = False 550 for ckey in ('fg', 'bg'): 551 color = group_config.get(ckey) 552 if not color: 553 # No color. Error was already reported when checking 554 # colorschemes. 555 return True 556 havemarks(color) 557 # Gradients are only allowed for function segments. Note that 558 # whether *either* color or gradient exists should have been 559 # already checked 560 hascolor = color in data['colors_config'].get('colors', {}) 561 hasgradient = color in data['colors_config'].get('gradients', {}) 562 if hasgradient: 563 hadgradient = True 564 if allow_gradients is False and not hascolor and hasgradient: 565 echoerr( 566 context='Error while checking highlight group in theme (key {key})'.format( 567 key=context.key), 568 context_mark=hl_group.mark, 569 problem='group {0} is using gradient {1} instead of a color'.format(hl_group, color), 570 problem_mark=color.mark 571 ) 572 return False 573 if allow_gradients == 'force' and not hadgradient: 574 echoerr( 575 context='Error while checking highlight group in theme (key {key})'.format( 576 key=context.key), 577 context_mark=hl_group.mark, 578 problem='group {0} should have at least one gradient color, but it has no'.format(hl_group), 579 problem_mark=group_config.mark 580 ) 581 return False 582 return True 583 584 585def hl_exists(hl_group, data, context, echoerr, allow_gradients=False): 586 havemarks(hl_group) 587 ext = data['ext'] 588 if ext not in data['colorscheme_configs']: 589 # No colorschemes. Error was already reported, no need to report it 590 # twice 591 return [] 592 r = [] 593 found = False 594 for colorscheme, cconfig in data['colorscheme_configs'][ext].items(): 595 if hl_group_in_colorscheme(hl_group, cconfig, allow_gradients, data, context, echoerr): 596 found = True 597 else: 598 r.append(colorscheme) 599 if not found: 600 pass 601 return r 602 603 604def check_highlight_group(hl_group, data, context, echoerr): 605 havemarks(hl_group) 606 r = hl_exists(hl_group, data, context, echoerr) 607 if r: 608 echoerr( 609 context='Error while checking theme (key {key})'.format(key=context.key), 610 problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( 611 hl_group, list_sep.join(r)), 612 problem_mark=hl_group.mark 613 ) 614 return True, False, True 615 return True, False, False 616 617 618def check_highlight_groups(hl_groups, data, context, echoerr): 619 havemarks(hl_groups) 620 rs = [hl_exists(hl_group, data, context, echoerr) for hl_group in hl_groups] 621 if all(rs): 622 echoerr( 623 context='Error while checking theme (key {key})'.format(key=context.key), 624 problem='found highlight groups list ({0}) with all groups not defined in some colorschemes'.format( 625 list_sep.join((unicode(h) for h in hl_groups))), 626 problem_mark=hl_groups.mark 627 ) 628 for r, hl_group in zip(rs, hl_groups): 629 echoerr( 630 context='Error while checking theme (key {key})'.format(key=context.key), 631 problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( 632 hl_group, list_sep.join(r)), 633 problem_mark=hl_group.mark 634 ) 635 return True, False, True 636 return True, False, False 637 638 639def check_segment_data_key(key, data, context, echoerr): 640 havemarks(key) 641 has_module_name = '.' in key 642 found = False 643 for ext, theme in list_themes(data, context): 644 for segments in theme.get('segments', {}).values(): 645 for segment in segments: 646 if 'name' in segment: 647 if key == segment['name']: 648 found = True 649 break 650 else: 651 function_name = segment.get('function') 652 if function_name: 653 module, function_name = get_function_strings(function_name, ((None, theme),), ext) 654 if has_module_name: 655 full_name = module + '.' + function_name 656 if key == full_name: 657 found = True 658 break 659 else: 660 if key == function_name: 661 found = True 662 break 663 if found: 664 break 665 if found: 666 break 667 else: 668 if data['theme_type'] != 'top': 669 echoerr(context='Error while checking segment data', 670 problem='found key {0} that cannot be associated with any segment'.format(key), 671 problem_mark=key.mark) 672 return True, False, True 673 674 return True, False, False 675 676 677threaded_args_specs = { 678 'interval': Spec().cmp('gt', 0.0), 679 'update_first': Spec().type(bool), 680 'shutdown_event': Spec().error('Shutdown event must be set by powerline'), 681} 682 683 684def check_args_variant(func, args, data, context, echoerr): 685 havemarks(args) 686 argspec = getconfigargspec(func) 687 present_args = set(args) 688 all_args = set(argspec.args) 689 required_args = set(argspec.args[:-len(argspec.defaults)]) 690 691 hadproblem = False 692 693 if required_args - present_args: 694 echoerr( 695 context='Error while checking segment arguments (key {key})'.format(key=context.key), 696 context_mark=args.mark, 697 problem='some of the required keys are missing: {0}'.format(list_sep.join(required_args - present_args)) 698 ) 699 hadproblem = True 700 701 if not all_args >= present_args: 702 echoerr(context='Error while checking segment arguments (key {key})'.format(key=context.key), 703 context_mark=args.mark, 704 problem='found unknown keys: {0}'.format(list_sep.join(present_args - all_args)), 705 problem_mark=next(iter(present_args - all_args)).mark) 706 hadproblem = True 707 708 if isinstance(func, ThreadedSegment): 709 for key in set(threaded_args_specs) & present_args: 710 proceed, khadproblem = threaded_args_specs[key].match( 711 args[key], 712 args.mark, 713 data, 714 context.enter_key(args, key), 715 echoerr 716 ) 717 if khadproblem: 718 hadproblem = True 719 if not proceed: 720 return hadproblem 721 722 return hadproblem 723 724 725def check_args(get_functions, args, data, context, echoerr): 726 new_echoerr = DelayedEchoErr(echoerr) 727 count = 0 728 hadproblem = False 729 for func in get_functions(data, context, new_echoerr): 730 count += 1 731 shadproblem = check_args_variant(func, args, data, context, echoerr) 732 if shadproblem: 733 hadproblem = True 734 735 if not count: 736 hadproblem = True 737 if new_echoerr: 738 new_echoerr.echo_all() 739 else: 740 echoerr(context='Error while checking segment arguments (key {key})'.format(key=context.key), 741 context_mark=context[-2][1].mark, 742 problem='no suitable segments found') 743 744 return True, False, hadproblem 745 746 747def get_one_segment_function(data, context, echoerr): 748 ext = data['ext'] 749 function_name = context[-2][1].get('function') 750 if function_name: 751 module, function_name = get_function_strings(function_name, context, ext) 752 func = import_segment(function_name, data, context, echoerr, module=module) 753 if func: 754 yield func 755 756 757common_names = defaultdict(set) 758 759 760def register_common_name(name, cmodule, cname): 761 s = cmodule + '.' + cname 762 cmodule_mark = Mark('<common name definition>', 1, 1, s, 1) 763 cname_mark = Mark('<common name definition>', 1, len(cmodule) + 1, s, len(cmodule) + 1) 764 common_names[name].add((MarkedUnicode(cmodule, cmodule_mark), MarkedUnicode(cname, cname_mark))) 765 766 767def get_all_possible_functions(data, context, echoerr): 768 name = context[-2][0] 769 module, name = name.rpartition('.')[::2] 770 if module: 771 func = import_segment(name, data, context, echoerr, module=module) 772 if func: 773 yield func 774 else: 775 if name in common_names: 776 for cmodule, cname in common_names[name]: 777 cfunc = import_segment(cname, data, context, echoerr, module=MarkedUnicode(cmodule, None)) 778 if cfunc: 779 yield cfunc 780 for ext, theme_config in list_themes(data, context): 781 for segments in theme_config.get('segments', {}).values(): 782 for segment in segments: 783 if segment.get('type', 'function') == 'function': 784 function_name = segment.get('function') 785 current_name = segment.get('name') 786 if function_name: 787 module, function_name = get_function_strings(function_name, ((None, theme_config),), ext) 788 if current_name == name or function_name == name: 789 func = import_segment(function_name, data, context, echoerr, module=module) 790 if func: 791 yield func 792 793 794def check_exinclude_function(name, data, context, echoerr): 795 ext = data['ext'] 796 module, name = name.rpartition('.')[::2] 797 if not module: 798 module = MarkedUnicode('powerline.selectors.' + ext, None) 799 func = import_function('selector', name, data, context, echoerr, module=module) 800 if not func: 801 return True, False, True 802 return True, False, False 803 804 805def check_log_file_level(this_level, data, context, echoerr): 806 '''Check handler level specified in :ref:`log_file key <config-common-log>` 807 808 This level must be greater or equal to the level in :ref:`log_level key 809 <config-common-log_level>`. 810 ''' 811 havemarks(this_level) 812 hadproblem = False 813 top_level = context[0][1].get('common', {}).get('log_level', 'WARNING') 814 top_level_str = top_level 815 top_level_mark = getattr(top_level, 'mark', None) 816 if ( 817 not isinstance(top_level, unicode) or not hasattr(logging, top_level) 818 or not isinstance(this_level, unicode) or not hasattr(logging, this_level) 819 ): 820 return True, False, hadproblem 821 top_level = getattr(logging, top_level) 822 this_level_str = this_level 823 this_level_mark = this_level.mark 824 this_level = getattr(logging, this_level) 825 if this_level < top_level: 826 echoerr( 827 context='Error while checking log level index (key {key})'.format( 828 key=context.key), 829 context_mark=this_level_mark, 830 problem='found level that is less critical then top level ({0} < {0})'.format( 831 this_level_str, top_level_str), 832 problem_mark=top_level_mark, 833 ) 834 hadproblem = True 835 return True, False, hadproblem 836 837 838def check_logging_handler(handler_name, data, context, echoerr): 839 havemarks(handler_name) 840 import_paths = [os.path.expanduser(path) for path in context[0][1].get('common', {}).get('paths', [])] 841 842 handler_module, separator, handler_class = handler_name.rpartition('.') 843 if not separator: 844 handler_module = 'logging.handlers' 845 handler_class = handler_name 846 with WithPath(import_paths): 847 try: 848 handler = getattr(__import__(str(handler_module), fromlist=[str(handler_class)]), str(handler_class)) 849 except ImportError: 850 echoerr(context='Error while loading logger class (key {key})'.format(key=context.key), 851 problem='failed to load module {0}'.format(handler_module), 852 problem_mark=handler_name.mark) 853 return True, False, True 854 except AttributeError: 855 echoerr(context='Error while loading logger class (key {key})'.format(key=context.key), 856 problem='failed to load handler class {0}'.format(handler_class), 857 problem_mark=handler_name.mark) 858 return True, False, True 859 860 if not issubclass(handler, logging.Handler): 861 echoerr(context='Error while loading logger class (key {key})'.format(key=context.key), 862 problem='loaded class {0} is not a logging.Handler subclass'.format(handler_class), 863 problem_mark=handler_name.mark) 864 return True, False, True 865 866 return True, False, False 867