root/galaxy-central/eggs/nose-0.11.1-py2.6.egg/nose/util.py

リビジョン 3, 19.7 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1"""Utility functions and classes used by nose internally.
2"""
3import inspect
4import itertools
5import logging
6import os
7import re
8import sys
9import types
10import unittest
11from types import ClassType, TypeType
12
13try:
14    from compiler.consts import CO_GENERATOR
15except ImportError:
16    # IronPython doesn't have a complier module
17    CO_GENERATOR=0x20
18   
19log = logging.getLogger('nose')
20
21ident_re = re.compile(r'^[A-Za-z_][A-Za-z0-9_.]*$')
22class_types = (ClassType, TypeType)
23skip_pattern = r"(?:\.svn)|(?:[^.]+\.py[co])|(?:.*~)|(?:.*\$py\.class)"
24
25try:
26    set()
27    set = set # make from nose.util import set happy
28except NameError:
29    try:
30        from sets import Set as set
31    except ImportError:
32        pass
33
34
35def ls_tree(dir_path="",
36            skip_pattern=skip_pattern,
37            indent="|-- ", branch_indent="|   ",
38            last_indent="`-- ", last_branch_indent="    "):
39    # TODO: empty directories look like non-directory files
40    return "\n".join(_ls_tree_lines(dir_path, skip_pattern,
41                                    indent, branch_indent,
42                                    last_indent, last_branch_indent))
43
44
45def _ls_tree_lines(dir_path, skip_pattern,
46                   indent, branch_indent, last_indent, last_branch_indent):
47    if dir_path == "":
48        dir_path = os.getcwd()
49
50    lines = []
51
52    names = os.listdir(dir_path)
53    names.sort()
54    dirs, nondirs = [], []
55    for name in names:
56        if re.match(skip_pattern, name):
57            continue
58        if os.path.isdir(os.path.join(dir_path, name)):
59            dirs.append(name)
60        else:
61            nondirs.append(name)
62
63    # list non-directories first
64    entries = list(itertools.chain([(name, False) for name in nondirs],
65                                   [(name, True) for name in dirs]))
66    def ls_entry(name, is_dir, ind, branch_ind):
67        if not is_dir:
68            yield ind + name
69        else:
70            path = os.path.join(dir_path, name)
71            if not os.path.islink(path):
72                yield ind + name
73                subtree = _ls_tree_lines(path, skip_pattern,
74                                         indent, branch_indent,
75                                         last_indent, last_branch_indent)
76                for x in subtree:
77                    yield branch_ind + x
78    for name, is_dir in entries[:-1]:
79        for line in ls_entry(name, is_dir, indent, branch_indent):
80            yield line
81    if entries:
82        name, is_dir = entries[-1]
83        for line in ls_entry(name, is_dir, last_indent, last_branch_indent):
84            yield line
85
86
87def absdir(path):
88    """Return absolute, normalized path to directory, if it exists; None
89    otherwise.
90    """
91    if not os.path.isabs(path):
92        path = os.path.normpath(os.path.abspath(os.path.join(os.getcwd(),
93                                                             path)))
94    if path is None or not os.path.isdir(path):
95        return None
96    return path
97
98
99def absfile(path, where=None):
100    """Return absolute, normalized path to file (optionally in directory
101    where), or None if the file can't be found either in where or the current
102    working directory.
103    """
104    orig = path
105    if where is None:
106        where = os.getcwd()
107    if isinstance(where, list) or isinstance(where, tuple):
108        for maybe_path in where:
109            maybe_abs = absfile(path, maybe_path)
110            if maybe_abs is not None:
111                return maybe_abs
112        return None
113    if not os.path.isabs(path):
114        path = os.path.normpath(os.path.abspath(os.path.join(where, path)))
115    if path is None or not os.path.exists(path):
116        if where != os.getcwd():
117            # try the cwd instead
118            path = os.path.normpath(os.path.abspath(os.path.join(os.getcwd(),
119                                                                 orig)))
120    if path is None or not os.path.exists(path):
121        return None
122    if os.path.isdir(path):
123        # might want an __init__.py from pacakge
124        init = os.path.join(path,'__init__.py')
125        if os.path.isfile(init):
126            return init
127    elif os.path.isfile(path):
128        return path
129    return None
130
131
132def anyp(predicate, iterable):
133    for item in iterable:
134        if predicate(item):
135            return True
136    return False
137
138
139def file_like(name):
140    """A name is file-like if it is a path that exists, or it has a
141    directory part, or it ends in .py, or it isn't a legal python
142    identifier.
143    """
144    return (os.path.exists(name)
145            or os.path.dirname(name)
146            or name.endswith('.py')
147            or not ident_re.match(os.path.splitext(name)[0]))
148
149
150def cmp_lineno(a, b):
151    """Compare functions by their line numbers.
152
153    >>> cmp_lineno(isgenerator, ispackage)
154    -1
155    >>> cmp_lineno(ispackage, isgenerator)
156    1
157    >>> cmp_lineno(isgenerator, isgenerator)
158    0
159    """
160    return cmp(func_lineno(a), func_lineno(b))
161
162
163def func_lineno(func):
164    """Get the line number of a function. First looks for
165    compat_co_firstlineno, then func_code.co_first_lineno.
166    """
167    try:
168        return func.compat_co_firstlineno
169    except AttributeError:
170        try:
171            return func.func_code.co_firstlineno
172        except AttributeError:
173            return -1
174
175
176def isclass(obj):
177    """Is obj a class? Inspect's isclass is too liberal and returns True
178    for objects that can't be subclasses of anything.
179    """
180    obj_type = type(obj)
181    return obj_type in class_types or issubclass(obj_type, type)
182
183
184def isgenerator(func):
185    try:
186        return func.func_code.co_flags & CO_GENERATOR != 0
187    except AttributeError:
188        return False
189# backwards compat (issue #64)
190is_generator = isgenerator
191
192
193def ispackage(path):
194    """
195    Is this path a package directory?
196
197    >>> ispackage('nose')
198    True
199    >>> ispackage('unit_tests')
200    False
201    >>> ispackage('nose/plugins')
202    True
203    >>> ispackage('nose/loader.py')
204    False
205    """
206    if os.path.isdir(path):
207        # at least the end of the path must be a legal python identifier
208        # and __init__.py[co] must exist
209        end = os.path.basename(path)
210        if ident_re.match(end):
211            for init in ('__init__.py', '__init__.pyc', '__init__.pyo'):
212                if os.path.isfile(os.path.join(path, init)):
213                    return True
214            if sys.platform.startswith('java') and \
215                    os.path.isfile(os.path.join(path, '__init__$py.class')):
216                return True
217    return False
218
219
220def isproperty(obj):
221    """
222    Is this a property?
223
224    >>> class Foo:
225    ...     def got(self):
226    ...         return 2
227    ...     def get(self):
228    ...         return 1
229    ...     get = property(get)
230
231    >>> isproperty(Foo.got)
232    False
233    >>> isproperty(Foo.get)
234    True
235    """
236    return type(obj) == property
237
238
239def getfilename(package, relativeTo=None):
240    """Find the python source file for a package, relative to a
241    particular directory (defaults to current working directory if not
242    given).
243    """
244    if relativeTo is None:
245        relativeTo = os.getcwd()
246    path = os.path.join(relativeTo, os.sep.join(package.split('.')))
247    suffixes = ('/__init__.py', '.py')
248    for suffix in suffixes:
249        filename = path + suffix
250        if os.path.exists(filename):
251            return filename
252    return None
253
254
255def getpackage(filename):
256    """
257    Find the full dotted package name for a given python source file
258    name. Returns None if the file is not a python source file.
259
260    >>> getpackage('foo.py')
261    'foo'
262    >>> getpackage('biff/baf.py')
263    'baf'
264    >>> getpackage('nose/util.py')
265    'nose.util'
266
267    Works for directories too.
268
269    >>> getpackage('nose')
270    'nose'
271    >>> getpackage('nose/plugins')
272    'nose.plugins'
273
274    And __init__ files stuck onto directories
275
276    >>> getpackage('nose/plugins/__init__.py')
277    'nose.plugins'
278
279    Absolute paths also work.
280
281    >>> path = os.path.abspath(os.path.join('nose', 'plugins'))
282    >>> getpackage(path)
283    'nose.plugins'
284    """
285    src_file = src(filename)
286    if not src_file.endswith('.py') and not ispackage(src_file):
287        return None
288    base, ext = os.path.splitext(os.path.basename(src_file))
289    if base == '__init__':
290        mod_parts = []
291    else:
292        mod_parts = [base]
293    path, part = os.path.split(os.path.split(src_file)[0])
294    while part:
295        if ispackage(os.path.join(path, part)):
296            mod_parts.append(part)
297        else:
298            break
299        path, part = os.path.split(path)
300    mod_parts.reverse()
301    return '.'.join(mod_parts)
302
303
304def ln(label):
305    """Draw a 70-char-wide divider, with label in the middle.
306
307    >>> ln('hello there')
308    '---------------------------- hello there -----------------------------'
309    """
310    label_len = len(label) + 2
311    chunk = (70 - label_len) / 2
312    out = '%s %s %s' % ('-' * chunk, label, '-' * chunk)
313    pad = 70 - len(out)
314    if pad > 0:
315        out = out + ('-' * pad)
316    return out
317
318
319def resolve_name(name, module=None):
320    """Resolve a dotted name to a module and its parts. This is stolen
321    wholesale from unittest.TestLoader.loadTestByName.
322
323    >>> resolve_name('nose.util') #doctest: +ELLIPSIS
324    <module 'nose.util' from...>
325    >>> resolve_name('nose.util.resolve_name') #doctest: +ELLIPSIS
326    <function resolve_name at...>
327    """
328    parts = name.split('.')
329    parts_copy = parts[:]
330    if module is None:
331        while parts_copy:
332            try:
333                log.debug("__import__ %s", name)
334                module = __import__('.'.join(parts_copy))
335                break
336            except ImportError:
337                del parts_copy[-1]
338                if not parts_copy:
339                    raise
340        parts = parts[1:]
341    obj = module
342    log.debug("resolve: %s, %s, %s, %s", parts, name, obj, module)
343    for part in parts:
344        obj = getattr(obj, part)
345    return obj
346
347
348def split_test_name(test):
349    """Split a test name into a 3-tuple containing file, module, and callable
350    names, any of which (but not all) may be blank.
351
352    Test names are in the form:
353
354    file_or_module:callable
355
356    Either side of the : may be dotted. To change the splitting behavior, you
357    can alter nose.util.split_test_re.
358    """
359    norm = os.path.normpath
360    file_or_mod = test
361    fn = None
362    if not ':' in test:
363        # only a file or mod part
364        if file_like(test):
365            return (norm(test), None, None)
366        else:
367            return (None, test, None)
368
369    # could be path|mod:callable, or a : in the file path someplace
370    head, tail = os.path.split(test)
371    if not head:
372        # this is a case like 'foo:bar' -- generally a module
373        # name followed by a callable, but also may be a windows
374        # drive letter followed by a path
375        try:
376            file_or_mod, fn = test.split(':')
377            if file_like(fn):
378                # must be a funny path
379                file_or_mod, fn = test, None
380        except ValueError:
381            # more than one : in the test
382            # this is a case like c:\some\path.py:a_test
383            parts = test.split(':')
384            if len(parts[0]) == 1:
385                file_or_mod, fn = ':'.join(parts[:-1]), parts[-1]
386            else:
387                # nonsense like foo:bar:baz
388                raise ValueError("Test name '%s' could not be parsed. Please "
389                                 "format test names as path:callable or "
390                                 "module:callable.")
391    elif not tail:
392        # this is a case like 'foo:bar/'
393        # : must be part of the file path, so ignore it
394        file_or_mod = test
395    else:
396        if ':' in tail:
397            file_part, fn = tail.split(':')
398        else:
399            file_part = tail
400        file_or_mod = os.sep.join([head, file_part])
401    if file_or_mod:
402        if file_like(file_or_mod):
403            return (norm(file_or_mod), None, fn)
404        else:
405            return (None, file_or_mod, fn)
406    else:
407        return (None, None, fn)
408split_test_name.__test__ = False # do not collect
409
410
411def test_address(test):
412    """Find the test address for a test, which may be a module, filename,
413    class, method or function.
414    """
415    if hasattr(test, "address"):
416        return test.address()
417    # type-based polymorphism sucks in general, but I believe is
418    # appropriate here
419    t = type(test)
420    file = module = call = None
421    if t == types.ModuleType:
422        file = getattr(test, '__file__', None)
423        module = getattr(test, '__name__', None)
424        return (src(file), module, call)
425    if t == types.FunctionType or issubclass(t, type) or t == types.ClassType:
426        module = getattr(test, '__module__', None)
427        if module is not None:
428            m = sys.modules[module]
429            file = getattr(m, '__file__', None)
430            if file is not None:
431                file = os.path.abspath(file)
432        call = getattr(test, '__name__', None)
433        return (src(file), module, call)
434    if t == types.InstanceType:
435        return test_address(test.__class__)
436    if t == types.MethodType:
437        cls_adr = test_address(test.im_class)
438        return (src(cls_adr[0]), cls_adr[1],
439                "%s.%s" % (cls_adr[2], test.__name__))
440    # handle unittest.TestCase instances
441    if isinstance(test, unittest.TestCase):
442        if hasattr(test, '_FunctionTestCase__testFunc'):
443            # unittest FunctionTestCase
444            return test_address(test._FunctionTestCase__testFunc)
445        # regular unittest.TestCase
446        cls_adr = test_address(test.__class__)
447        # 2.5 compat: __testMethodName changed to _testMethodName
448        try:
449            method_name = test._TestCase__testMethodName
450        except AttributeError:
451            method_name = test._testMethodName
452        return (src(cls_adr[0]), cls_adr[1],
453                "%s.%s" % (cls_adr[2], method_name))
454    raise TypeError("I don't know what %s is (%s)" % (test, t))
455test_address.__test__ = False # do not collect
456
457
458def try_run(obj, names):
459    """Given a list of possible method names, try to run them with the
460    provided object. Keep going until something works. Used to run
461    setup/teardown methods for module, package, and function tests.
462    """
463    for name in names:
464        func = getattr(obj, name, None)
465        if func is not None:
466            if type(obj) == types.ModuleType:
467                # py.test compatibility
468                try:
469                    args, varargs, varkw, defaults = inspect.getargspec(func)
470                except TypeError:
471                    # Not a function. If it's callable, call it anyway
472                    if hasattr(func, '__call__'):
473                        func = func.__call__
474                    try:
475                        args, varargs, varkw, defaults = \
476                            inspect.getargspec(func)
477                        args.pop(0) # pop the self off
478                    except TypeError:
479                        raise TypeError("Attribute %s of %r is not a python "
480                                        "function. Only functions or callables"
481                                        " may be used as fixtures." %
482                                        (name, obj))
483                if len(args):
484                    log.debug("call fixture %s.%s(%s)", obj, name, obj)
485                    return func(obj)
486            log.debug("call fixture %s.%s", obj, name)
487            return func()
488
489
490def src(filename):
491    """Find the python source file for a .pyc, .pyo or $py.class file on
492    jython. Returns the filename provided if it is not a python source
493    file.
494    """
495    if filename is None:
496        return filename
497    if sys.platform.startswith('java') and filename.endswith('$py.class'):
498        return '.'.join((filename[:-9], 'py'))
499    base, ext = os.path.splitext(filename)
500    if ext in ('.pyc', '.pyo', '.py'):
501        return '.'.join((base, 'py'))
502    return filename
503
504
505def match_last(a, b, regex):
506    """Sort compare function that puts items that match a
507    regular expression last.
508
509    >>> from nose.config import Config
510    >>> c = Config()
511    >>> regex = c.testMatch
512    >>> entries = ['.', '..', 'a_test', 'src', 'lib', 'test', 'foo.py']
513    >>> entries.sort(lambda a, b: match_last(a, b, regex))
514    >>> entries
515    ['.', '..', 'foo.py', 'lib', 'src', 'a_test', 'test']
516    """
517    if regex.search(a) and not regex.search(b):
518        return 1
519    elif regex.search(b) and not regex.search(a):
520        return -1
521    return cmp(a, b)
522
523
524def tolist(val):
525    """Convert a value that may be a list or a (possibly comma-separated)
526    string into a list. The exception: None is returned as None, not [None].
527
528    >>> tolist(["one", "two"])
529    ['one', 'two']
530    >>> tolist("hello")
531    ['hello']
532    >>> tolist("separate,values, with, commas,  spaces , are    ,ok")
533    ['separate', 'values', 'with', 'commas', 'spaces', 'are', 'ok']
534    """
535    if val is None:
536        return None
537    try:
538        # might already be a list
539        val.extend([])
540        return val
541    except AttributeError:
542        pass
543    # might be a string
544    try:
545        return re.split(r'\s*,\s*', val)
546    except TypeError:
547        # who knows...
548        return list(val)
549
550
551class odict(dict):
552    """Simple ordered dict implementation, based on:
553
554    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
555    """
556    def __init__(self, *arg, **kw):
557        self._keys = []
558        super(odict, self).__init__(*arg, **kw)
559
560    def __delitem__(self, key):
561        super(odict, self).__delitem__(key)
562        self._keys.remove(key)
563
564    def __setitem__(self, key, item):
565        super(odict, self).__setitem__(key, item)
566        if key not in self._keys:
567            self._keys.append(key)
568
569    def __str__(self):
570        return "{%s}" % ', '.join(["%r: %r" % (k, v) for k, v in self.items()])
571
572    def clear(self):
573        super(odict, self).clear()
574        self._keys = []
575
576    def copy(self):
577        d = super(odict, self).copy()
578        d._keys = self._keys[:]
579        return d
580
581    def items(self):
582        return zip(self._keys, self.values())
583
584    def keys(self):
585        return self._keys[:]
586
587    def setdefault(self, key, failobj=None):
588        item = super(odict, self).setdefault(key, failobj)
589        if key not in self._keys:
590            self._keys.append(key)
591        return item
592
593    def update(self, dict):
594        super(odict, self).update(dict)
595        for key in dict.keys():
596            if key not in self._keys:
597                self._keys.append(key)
598
599    def values(self):
600        return map(self.get, self._keys)
601
602
603def transplant_func(func, module):
604    """
605    Make a function imported from module A appear as if it is located
606    in module B.
607
608    >>> from pprint import pprint
609    >>> pprint.__module__
610    'pprint'
611    >>> pp = transplant_func(pprint, __name__)
612    >>> pp.__module__
613    'nose.util'
614
615    The original function is not modified.
616
617    >>> pprint.__module__
618    'pprint'
619
620    Calling the transplanted function calls the original.
621
622    >>> pp([1, 2])
623    [1, 2]
624    >>> pprint([1,2])
625    [1, 2]
626
627    """
628    from nose.tools import make_decorator
629    def newfunc(*arg, **kw):
630        return func(*arg, **kw)
631
632    newfunc = make_decorator(func)(newfunc)
633    newfunc.__module__ = module
634    return newfunc
635
636
637def transplant_class(cls, module):
638    """
639    Make a class appear to reside in `module`, rather than the module in which
640    it is actually defined.
641
642    >>> from nose.failure import Failure
643    >>> Failure.__module__
644    'nose.failure'
645    >>> Nf = transplant_class(Failure, __name__)
646    >>> Nf.__module__
647    'nose.util'
648    >>> Nf.__name__
649    'Failure'
650
651    """
652    class C(cls):
653        pass
654    C.__module__ = module
655    C.__name__ = cls.__name__
656    return C
657
658
659def safe_str(val, encoding='utf-8'):
660    try:
661        return str(val)
662    except UnicodeEncodeError:
663        if isinstance(val, Exception):
664            return ' '.join([safe_str(arg, encoding)
665                             for arg in val])
666        return unicode(val).encode(encoding)
667
668   
669if __name__ == '__main__':
670    import doctest
671    doctest.testmod()
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。