| 398 | | |
|---|
| 399 | | |
|---|
| 400 | | #----------------------------------------------------------------------------- |
|---|
| 401 | | # python code execution |
|---|
| 402 | | |
|---|
| 403 | | |
|---|
| 404 | | def run_magic_syspath(argv=None, |
|---|
| 405 | | import_modules=False, run_last_module=True): |
|---|
| 406 | | """Run a module using a magicaly extended sys.path. |
|---|
| 407 | | |
|---|
| 408 | | Discovers additional package paths by searching under directories listed as |
|---|
| 409 | | non option arguments. Discovery is egg aware: it takes care to include only |
|---|
| 410 | | the *best* version of each egg and only those eggs that match the python |
|---|
| 411 | | interpreters version. |
|---|
| 412 | | |
|---|
| 413 | | If the last argument names a legitemate python module then sys.path is |
|---|
| 414 | | extended with the discovered paths, sys.argv is adjusted to reflect the |
|---|
| 415 | | module name and the remaining arguments. Then runpy.run_module is used to |
|---|
| 416 | | execute the module in this magicaly discovered path. |
|---|
| 417 | | |
|---|
| 418 | | If any non option argument, other than the last, identifies a python module |
|---|
| 419 | | then sys.path is updated and an attempt to import the module is made. This |
|---|
| 420 | | feature allows import of packages whose import time behaviour would be |
|---|
| 421 | | adversly affected by any paths added on behalf of subsequent modules. Note |
|---|
| 422 | | that you can disable this by setting `import_modules=False` and |
|---|
| 423 | | `run_last_module=True`. This will defer all import behaviour to the module |
|---|
| 424 | | you chose to *run*. |
|---|
| 425 | | |
|---|
| 426 | | If the last argument is not a python package then two lists are returned. |
|---|
| 427 | | The first list contains the discovered path and the second list contains |
|---|
| 428 | | any modules that were imported as it was discovered. The second list will |
|---|
| 429 | | allways be empty if `import_modules` is False. |
|---|
| 430 | | |
|---|
| 431 | | TODO: examples |
|---|
| 432 | | |
|---|
| 433 | | """ |
|---|
| 434 | | |
|---|
| 435 | | argv = argv or sys.argv[:] |
|---|
| 436 | | lenargv = len(argv) |
|---|
| 437 | | if lenargv < 2: |
|---|
| 438 | | sys.exit(-1) |
|---|
| 439 | | |
|---|
| 440 | | ia=1 |
|---|
| 441 | | for i in range(lenargv - 1): |
|---|
| 442 | | ia = i + 1 |
|---|
| 443 | | a = argv[ia] |
|---|
| 444 | | if a == '--': |
|---|
| 445 | | del argv[ia] |
|---|
| 446 | | break |
|---|
| 447 | | elif a[:2] == '--' or a[:1] == '-': |
|---|
| 448 | | break |
|---|
| 449 | | else: |
|---|
| 450 | | ia=lenargv |
|---|
| 451 | | |
|---|
| 452 | | minfo = None |
|---|
| 453 | | |
|---|
| 454 | | searchpaths = [] |
|---|
| 455 | | pthset = set([]) |
|---|
| 456 | | pathsadded = [] |
|---|
| 457 | | pthextend = [] |
|---|
| 458 | | sys_path_insertpos = 0 |
|---|
| 459 | | |
|---|
| 460 | | imported = [] # hold on to the references. |
|---|
| 461 | | |
|---|
| 462 | | for i, a in enumerate(argv[1:ia]): |
|---|
| 463 | | |
|---|
| 464 | | minfo = path_moduleinfo(a) |
|---|
| 465 | | if minfo: |
|---|
| 466 | | # if its a legitemate python module file, import it with the |
|---|
| 467 | | # path we have discovered so far. |
|---|
| 468 | | if minfo[1] in sys.modules: |
|---|
| 469 | | continue |
|---|
| 470 | | |
|---|
| 471 | | if minfo[0] not in pthset: |
|---|
| 472 | | pthextend.append(minfo[0]) |
|---|
| 473 | | pthset.add(minfo[0]) |
|---|
| 474 | | |
|---|
| 475 | | # Don't import modules or update sys.path if import_modules is |
|---|
| 476 | | # False |
|---|
| 477 | | if not import_modules: |
|---|
| 478 | | continue |
|---|
| 479 | | |
|---|
| 480 | | # If the last argument is a module, then dont import it. We will |
|---|
| 481 | | # run it instead. |
|---|
| 482 | | if i+2 == ia: |
|---|
| 483 | | continue |
|---|
| 484 | | |
|---|
| 485 | | newpaths = find_package_paths(pth=pthset, |
|---|
| 486 | | *searchpaths |
|---|
| 487 | | ) |
|---|
| 488 | | pthextend.extend(newpaths) |
|---|
| 489 | | |
|---|
| 490 | | sys.path[sys_path_insertpos:sys_path_insertpos |
|---|
| 491 | | ] = pthextend[:] |
|---|
| 492 | | sys_path_insertpos += len(pthextend) |
|---|
| 493 | | |
|---|
| 494 | | pathsadded.extend(newpaths) |
|---|
| 495 | | pthextend[:] = [] |
|---|
| 496 | | searchpaths[:] = [] |
|---|
| 497 | | |
|---|
| 498 | | imported.append(__import__(minfo[1])) |
|---|
| 499 | | |
|---|
| 500 | | minfo = None |
|---|
| 501 | | continue |
|---|
| 502 | | |
|---|
| 503 | | else: |
|---|
| 504 | | searchpaths.append(a) |
|---|
| 505 | | |
|---|
| 506 | | |
|---|
| 507 | | newpaths = find_package_paths(pth=pthset, |
|---|
| 508 | | *searchpaths |
|---|
| 509 | | ) |
|---|
| 510 | | |
|---|
| 511 | | pthextend.extend(newpaths) |
|---|
| 512 | | |
|---|
| 513 | | if import_modules or run_last_module: |
|---|
| 514 | | sys.path[sys_path_insertpos:sys_path_insertpos |
|---|
| 515 | | ] = pthextend[:] |
|---|
| 516 | | |
|---|
| 517 | | pathsadded.extend(newpaths) |
|---|
| 518 | | |
|---|
| 519 | | if not run_last_module: |
|---|
| 520 | | return pathsadded, imported |
|---|
| 521 | | |
|---|
| 522 | | if minfo: |
|---|
| 523 | | sys.argv[:] = [] |
|---|
| 524 | | sys.argv.append(minfo[1]) |
|---|
| 525 | | sys.argv.extend(argv[ia:]) |
|---|
| 526 | | run_module(sys.argv[0], run_name='__main__', alter_sys=True) |
|---|
| 527 | | |
|---|
| 528 | | return pathsadded, imported |
|---|
| | 672 | def run_magic_syspath(argv=None, run_last_module=True): |
|---|
| | 673 | """Run a module using a magicaly extended sys.path. |
|---|
| | 674 | |
|---|
| | 675 | Discovers additional package paths by searching under directories listed as |
|---|
| | 676 | non option arguments. Discovery is egg aware: it takes care to include only |
|---|
| | 677 | the *best* version of each egg and only those eggs that match the python |
|---|
| | 678 | interpreters version. |
|---|
| | 679 | |
|---|
| | 680 | If the last argument names a legitemate python module then it will be |
|---|
| | 681 | executed using the `runpy.run_module` helper from the standard lib. This |
|---|
| | 682 | feature can be disabled by passing a false value for `run_last_module`. |
|---|
| | 683 | |
|---|
| | 684 | If any `interior` argument identifies a python module then its containing |
|---|
| | 685 | directory is added to the path extension. |
|---|
| | 686 | |
|---|
| | 687 | The extension path discovered by this api consists of unique paths in order |
|---|
| | 688 | of discovery. Where egg directories or archive files are encountered care |
|---|
| | 689 | is taken to ensure that eggs which are incompatible with the current |
|---|
| | 690 | `sys.executable` are *excluded* and only the *best* available version for |
|---|
| | 691 | each project is *included*. The measure of "best available" is the same as |
|---|
| | 692 | used by pkg_resources.py from the setuptools project. |
|---|
| | 693 | |
|---|
| | 694 | |
|---|
| | 695 | :Returns: |
|---|
| | 696 | The discovered extension path. But note that if `run_last_module` is |
|---|
| | 697 | true it resonably likely that this function will *not return*. |
|---|
| | 698 | |
|---|
| | 699 | TODO: examples |
|---|
| | 700 | |
|---|
| | 701 | """ |
|---|
| | 702 | |
|---|
| | 703 | argv = argv or sys.argv[:] |
|---|
| | 704 | |
|---|
| | 705 | pthextend = [] |
|---|
| | 706 | searchpaths = [] |
|---|
| | 707 | pthset = set([]) |
|---|
| | 708 | |
|---|
| | 709 | minfo = None |
|---|
| | 710 | for ia, a in enumerate_argv_args(argv, 1): |
|---|
| | 711 | if a is None: |
|---|
| | 712 | continue |
|---|
| | 713 | minfo = path_moduleinfo(a) |
|---|
| | 714 | if minfo: |
|---|
| | 715 | # if its a legitemate python module file, import it with the |
|---|
| | 716 | # path we have discovered so far. |
|---|
| | 717 | if minfo[1] in sys.modules: |
|---|
| | 718 | continue |
|---|
| | 719 | |
|---|
| | 720 | a = minfo[0] |
|---|
| | 721 | if a not in pthset: |
|---|
| | 722 | pthextend.append(a) |
|---|
| | 723 | pthset.add(a) |
|---|
| | 724 | |
|---|
| | 725 | else: |
|---|
| | 726 | searchpaths.append(a) |
|---|
| | 727 | |
|---|
| | 728 | newpaths = find_package_paths(pth=pthset, |
|---|
| | 729 | *searchpaths |
|---|
| | 730 | ) |
|---|
| | 731 | pthextend.extend(newpaths) |
|---|
| | 732 | |
|---|
| | 733 | if run_last_module and minfo: |
|---|
| | 734 | sys.path[0:0] = pthextend[:] |
|---|
| | 735 | sys.argv[:] = [] |
|---|
| | 736 | sys.argv.append(minfo[1]) |
|---|
| | 737 | sys.argv.extend(argv[ia:]) |
|---|
| | 738 | return run_module(sys.argv[0], run_name='__main__', alter_sys=True) |
|---|
| | 739 | |
|---|
| | 740 | else: |
|---|
| | 741 | return pthextend |
|---|
| | 742 | |
|---|
| | 743 | |
|---|
| | 744 | if __name__=='__main__': |
|---|
| | 745 | try: |
|---|
| | 746 | rval = run_magic_syspath() |
|---|
| | 747 | if rval and isinstance(rval, list): |
|---|
| | 748 | print os.pathsep.join(rval) |
|---|
| | 749 | except SystemExit: |
|---|
| | 750 | raise |
|---|
| | 751 | except: |
|---|
| | 752 | msg = exc_string() |
|---|
| | 753 | print msg |
|---|
| | 754 | sys.exit(-1) |
|---|
| | 755 | #EOF |
|---|
| | 756 | |
|---|