Guido van Rossum | d1df83b | 1994-03-07 11:45:36 +0000 | [diff] [blame] | 1 | # This module provides standard support for "packages". |
| 2 | # |
| 3 | # The idea is that large groups of related modules can be placed in |
| 4 | # their own subdirectory, which can be added to the Python search path |
| 5 | # in a relatively easy way. |
| 6 | # |
| 7 | # The current version takes a package name and searches the Python |
| 8 | # search path for a directory by that name, and if found adds it to |
| 9 | # the module search path (sys.path). It maintains a list of packages |
| 10 | # that have already been added so adding the same package many times |
| 11 | # is OK. |
| 12 | # |
| 13 | # It is intended to be used in a fairly stylized manner: each module |
| 14 | # that wants to use a particular package, say 'Foo', is supposed to |
| 15 | # contain the following code: |
| 16 | # |
| 17 | # from addpack import addpack |
| 18 | # addpack('Foo') |
| 19 | # <import modules from package Foo> |
| 20 | # |
| 21 | # Additional arguments, when present, provide additional places where |
| 22 | # to look for the package before trying sys.path (these may be either |
| 23 | # strings or lists/tuples of strings). Also, if the package name is a |
| 24 | # full pathname, first the last component is tried in the usual way, |
| 25 | # then the full pathname is tried last. If the package name is a |
| 26 | # *relative* pathname (UNIX: contains a slash but doesn't start with |
| 27 | # one), then nothing special is done. The packages "/foo/bar/bletch" |
| 28 | # and "bletch" are considered the same, but unrelated to "bar/bletch". |
| 29 | # |
| 30 | # If the algorithm finds more than one suitable subdirectory, all are |
| 31 | # added to the search path -- this makes it possible to override part |
| 32 | # of a package. The same path will not be added more than once. |
| 33 | # |
| 34 | # If no directory is found, ImportError is raised. |
| 35 | |
| 36 | _packs = {} # {pack: [pathname, ...], ...} |
| 37 | |
| 38 | def addpack(pack, *locations): |
| 39 | import os |
| 40 | if os.path.isabs(pack): |
| 41 | base = os.path.basename(pack) |
| 42 | else: |
| 43 | base = pack |
| 44 | if _packs.has_key(base): |
| 45 | return |
| 46 | import sys |
| 47 | path = [] |
| 48 | for loc in _flatten(locations) + sys.path: |
| 49 | fn = os.path.join(loc, base) |
| 50 | if fn not in path and os.path.isdir(fn): |
| 51 | path.append(fn) |
| 52 | if pack != base and pack not in path and os.path.isdir(pack): |
| 53 | path.append(pack) |
| 54 | if not path: raise ImportError, 'package ' + pack + ' not found' |
| 55 | _packs[base] = path |
| 56 | for fn in path: |
| 57 | if fn not in sys.path: |
| 58 | sys.path.append(fn) |
| 59 | |
| 60 | def _flatten(locations): |
| 61 | locs = [] |
| 62 | for loc in locations: |
| 63 | if type(loc) == type(''): |
| 64 | locs.append(loc) |
| 65 | else: |
| 66 | locs = locs + _flatten(loc) |
| 67 | return locs |