You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
2.8 KiB

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