|
| 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 |
0 commit comments