1 #=======================================================================
3 __version__
= '''0.0.14'''
4 __sub_version__
= '''20040326125114'''
5 __copyright__
= '''(c) Alex A. Naanou 2003'''
8 #-----------------------------------------------------------------------
10 from __future__
import generators
16 #-----------------------------------------------------------------------
18 PY_SUFFIXES
= imp
.get_suffixes()
21 #-----------------------------------------------------------------------
22 #-----------------------------------------------ImportDependencyError---
23 class ImportDependencyError(Exception):
29 #-----------------------------------------------------------------------
30 #--------------------------------------------------------_load_module---
31 # NOTE: this is a potential log/aspect point...
32 def _load_module(package_dir
, mod_name
):
38 # restrict the path the import path to avoid
39 # uncontrolled imports...
40 mod_dat
= imp
.find_module(mod_name
, [package_dir
])
41 module
= imp
.load_module(mod_name
, *mod_dat
)
43 if len(mod_dat
) > 1 and mod_dat
[0] != None:
45 return mod_name
, module
47 # cleanup... (is this needed???)
48 if len(mod_dat
) > 1 and mod_dat
[0] != None:
53 #--------------------------------------------------ispythonimportable---
54 def ispythonimportable(package_dir
, name
):
56 this will test if the module name is importable from package_dir.
58 mod_path
= os
.path
.join(package_dir
, name
)
59 # is directory and contains __init__.py?
60 if os
.path
.isdir(mod_path
) and \
61 True in [ os
.path
.exists(os
.path
.join(mod_path
, '__init__' + ext
[0])) \
62 for ext
in PY_SUFFIXES
]:
65 # is file -> is .py[cod]...
66 return True in [ os
.path
.exists(os
.path
.join(mod_path
, ext
[0])) \
67 for ext
in PY_SUFFIXES
]
71 #---------------------------------------------------------packageiter---
72 def packageiter(package_dir
, disable_file
='disabled.txt', disabled_packages
=None):
75 This will return importable (and enabled) package names (without importing).
76 this will return the names of all packages/modules under a given path (package_dir),
77 not containing the "disabled.txt" file (disable_file), one per iteration.
79 optional side-effects:
80 disabled_packages : if given, will contain the names of disabled modules
81 (e.g. modules that contained the "disabled.txt" file
83 NOTE: the above two parameters MUST either be of list type or None.
85 # some sanity checks...
86 if disabled_packages
!= None and type(disabled_packages
) != list:
87 raise TypeError, 'disabled_packages must either be of list type or None (got type "%s").' % type(disabled_packages
)
90 for mod
in os
.listdir(package_dir
):
92 if mod
.startswith('__init__.'):
95 mod_name
= mod
.split('.', 1)[0]
96 # include each name only once...
97 if mod_name
not in loaded_packages
.keys() + ['']:
98 # skip disabled plugins...
99 if os
.path
.exists(os
.path
.join(package_dir
, mod_name
, disable_file
)):
100 if disabled_packages
!= None:
101 disabled_packages
+= [mod_name
]
103 if ispythonimportable(package_dir
, mod_name
):
108 #---------------------------------------------------getpackagedepends---
109 def getpackagedepends(package_dir
, mod_name
, dependency_file
='depends.txt', forbidden_chars
=' -+=&*()^%$#@!~`,.'):
112 # see if the dependency file exists...
113 if not os
.path
.exists(os
.path
.join(package_dir
, mod_name
, dependency_file
)):
115 dep_file
= open(os
.path
.join(package_dir
, mod_name
, dependency_file
))
116 # parse dependency file...
117 deps
= [ s
.lstrip().split('#')[0].rstrip() \
119 if s
.split('#')[0].lstrip() != '' ]
121 # check for correctness...
122 if [ s
for s
in deps
if True in [ c
in s
for c
in forbidden_chars
] ]:
123 raise ImportDependencyError
, 'dependency file format error.'
128 #-----------------------------------------------------------------------
129 #---------------------------------------------------importpackageiter---
130 # TODO make this return more specific error data (e.g. name, exception,
132 def importpackageiter(package_dir
, disable_file
='disabled.txt', err_names
=None, disabled_packages
=None):
135 This is an import iterator.
136 this will import all packages/modules under a given path (package_dir),
137 not containing the "disabled.txt" file (disable_file), one per iteration, and
138 will return a tuple containing the module name and its object.
140 optional side-effects:
141 err_names : if given, will contain the names of modules that
142 generated ImportError.
143 disabled_packages : if given, will contain the names of disabled modules
144 (e.g. modules that contained the "disabled.txt" file
146 NOTE: the above two parameters MUST either be of list type or None.
148 # some sanity checks...
149 if err_names
!= None and type(err_names
) != list:
150 raise TypeError, 'err_names must either be of list type or None (got type "%s").' % type(err_names
)
152 for mod_name
in packageiter(package_dir
, disable_file
, disabled_packages
):
153 mod_name
, module
= _load_module(package_dir
, mod_name
)
155 yield mod_name
, module
156 elif err_names
!= None:
157 err_names
+= [mod_name
]
161 #-------------------------------------------importdependspackagesiter---
162 # TODO make this a generic dependency checker (objutils ???)
163 def importdependspackagesiter(package_dir
, disable_file
='disabled.txt',\
164 dependency_file
='depends.txt', err_names
=None,\
165 disabled_packages
=None):
168 This will import the modules in order of dependency.
171 def _loaddependsiter(path
, name
, wait_lst
, loaded_packages
, err_names
=None):
174 if name
not in loaded_packages
:
175 name
, mod
= _load_module(path
, name
)
176 if mod
== None and err_names
!= None:
179 loaded_packages
[name
] = mod
181 dependees
= wait_lst
.pop(name
, [])
182 for name
in dependees
:
183 # if module does not need anything else load
184 if [ m
for m
in wait_lst
.values() if name
in m
]:
187 for n
, m
in _loaddependsiter(path
, name
, wait_lst
, loaded_packages
, err_names
):
192 for mod_name
in packageiter(package_dir
, disable_file
, disabled_packages
):
194 deps
= getpackagedepends(package_dir
, mod_name
, dependency_file
)
195 # if all dependencies are loaded load package...
196 needs
= [ i
for i
in deps
if i
not in loaded_packages
]
197 # check if we depend on a faulty package...
198 err_needs
= [ i
for i
in needs
if i
in err_names
]
199 if err_names
!= None and err_names
:
200 raise ImportDependencyError
, 'failure in dependencies (failed: %s).' % err_names
205 wait_lst
[mod
] += [mod_name
]
207 wait_lst
[mod
] = [mod_name
]
209 for n
, m
in _loaddependsiter(package_dir
, mod_name
, wait_lst
, loaded_packages
, err_names
):
211 # check if the remainig data in wait list is looping deps...
213 # TODO do a more thorough check...
214 raise ImportDependencyError
, 'cyclic or unresolved demendencies in: %s.' % wait_lst
218 #=======================================================================
219 # vim:set ts=4 sw=4 nowrap :