1# originally inspired by "six" by Benjamin Peterson 2 3import inspect 4import sys 5 6 7if sys.version_info < (3,0): 8 text_type = unicode 9 binary_type = str 10 11 import StringIO 12 StringIO = BytesIO = StringIO.StringIO 13else: 14 text_type = str 15 binary_type = bytes 16 17 import io 18 StringIO = io.StringIO 19 BytesIO = io.BytesIO 20 21 22def getargspec_permissive(func): 23 """ 24 An `inspect.getargspec` with a relaxed sanity check to support Cython. 25 26 Motivation: 27 28 A Cython-compiled function is *not* an instance of Python's 29 types.FunctionType. That is the sanity check the standard Py2 30 library uses in `inspect.getargspec()`. So, an exception is raised 31 when calling `argh.dispatch_command(cythonCompiledFunc)`. However, 32 the CyFunctions do have perfectly usable `.func_code` and 33 `.func_defaults` which is all `inspect.getargspec` needs. 34 35 This function just copies `inspect.getargspec()` from the standard 36 library but relaxes the test to a more duck-typing one of having 37 both `.func_code` and `.func_defaults` attributes. 38 """ 39 if inspect.ismethod(func): 40 func = func.im_func 41 42 # Py2 Stdlib uses isfunction(func) which is too strict for Cython-compiled 43 # functions though such have perfectly usable func_code, func_defaults. 44 if not (hasattr(func, "func_code") and hasattr(func, "func_defaults")): 45 raise TypeError('{!r} missing func_code or func_defaults'.format(func)) 46 47 args, varargs, varkw = inspect.getargs(func.func_code) 48 return inspect.ArgSpec(args, varargs, varkw, func.func_defaults) 49 50 51if sys.version_info < (3,0): 52 getargspec = getargspec_permissive 53else: 54 # in Python 3 the basic getargspec doesn't support keyword-only arguments 55 # and annotations and raises ValueError if they are discovered 56 getargspec = inspect.getfullargspec 57 58 59class _PrimitiveOrderedDict(dict): 60 """ 61 A poor man's OrderedDict replacement for compatibility with Python 2.6. 62 Implements only the basic features. May easily break if non-overloaded 63 methods are used. 64 """ 65 def __init__(self, *args, **kwargs): 66 super(_PrimitiveOrderedDict, self).__init__(*args, **kwargs) 67 self._seq = [] 68 69 def __setitem__(self, key, value): 70 super(_PrimitiveOrderedDict, self).__setitem__(key, value) 71 if key not in self._seq: 72 self._seq.append(key) 73 74 def __delitem__(self, key): 75 super(_PrimitiveOrderedDict, self).__delitem__(key) 76 idx = self._seq.index(key) 77 del self._seq[idx] 78 79 def __iter__(self): 80 return iter(self._seq) 81 82 def keys(self): 83 return list(self) 84 85 def values(self): 86 return [self[k] for k in self] 87 88 89try: 90 from collections import OrderedDict 91except ImportError: 92 OrderedDict = _PrimitiveOrderedDict 93