ipy_completer.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #+
  2. #
  3. # This file is part of h5py, a low-level Python interface to the HDF5 library.
  4. #
  5. # Contributed by Darren Dale
  6. #
  7. # Copyright (C) 2009 Darren Dale
  8. #
  9. # http://h5py.org
  10. # License: BSD (See LICENSE.txt for full license)
  11. #
  12. #-
  13. # pylint: disable=eval-used,protected-access
  14. """
  15. This is the h5py completer extension for ipython. It is loaded by
  16. calling the function h5py.enable_ipython_completer() from within an
  17. interactive IPython session.
  18. It will let you do things like::
  19. f=File('foo.h5')
  20. f['<tab>
  21. # or:
  22. f['ite<tab>
  23. which will do tab completion based on the subgroups of `f`. Also::
  24. f['item1'].at<tab>
  25. will perform tab completion for the attributes in the usual way. This should
  26. also work::
  27. a = b = f['item1'].attrs.<tab>
  28. as should::
  29. f['item1/item2/it<tab>
  30. """
  31. import posixpath
  32. import re
  33. import readline
  34. from ._hl.attrs import AttributeManager
  35. from ._hl.base import HLObject
  36. try:
  37. # >=ipython-1.0
  38. from IPython import get_ipython
  39. except ImportError:
  40. try:
  41. # support >=ipython-0.11, <ipython-1.0
  42. from IPython.core.ipapi import get as get_ipython
  43. except ImportError:
  44. # support <ipython-0.11
  45. from IPython.ipapi import get as get_ipython
  46. try:
  47. # support >=ipython-0.11
  48. from IPython.utils import generics
  49. except ImportError:
  50. # support <ipython-0.11
  51. from IPython import generics
  52. try:
  53. from IPython.core.error import TryNext
  54. except ImportError:
  55. try:
  56. from IPython import TryNext
  57. except ImportError:
  58. from IPython.ipapi import TryNext
  59. re_attr_match = re.compile(r"(?:.*\=)?(.+\[.*\].*)\.(\w*)$")
  60. re_item_match = re.compile(r"""(?:.*\=)?(.*)\[(?P<s>['|"])(?!.*(?P=s))(.*)$""")
  61. re_object_match = re.compile(r"(?:.*\=)?(.+?)(?:\[)")
  62. def _retrieve_obj(name, context):
  63. """ Filter function for completion. """
  64. # we don't want to call any functions, but I couldn't find a robust regex
  65. # that filtered them without unintended side effects. So keys containing
  66. # "(" will not complete.
  67. if '(' in name:
  68. raise ValueError()
  69. try:
  70. # older versions of IPython:
  71. obj = eval(name, context.shell.user_ns)
  72. except AttributeError:
  73. # as of IPython-1.0:
  74. obj = eval(name, context.user_ns)
  75. return obj
  76. def h5py_item_completer(context, command):
  77. """Compute possible item matches for dict-like objects"""
  78. base, item = re_item_match.split(command)[1:4:2]
  79. try:
  80. obj = _retrieve_obj(base, context)
  81. except Exception:
  82. return []
  83. path, _ = posixpath.split(item)
  84. try:
  85. if path:
  86. items = (posixpath.join(path, name) for name in obj[path].keys())
  87. else:
  88. items = obj.keys()
  89. except AttributeError:
  90. return []
  91. items = list(items)
  92. readline.set_completer_delims(' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?')
  93. return [i for i in items if i[:len(item)] == item]
  94. def h5py_attr_completer(context, command):
  95. """Compute possible attr matches for nested dict-like objects"""
  96. base, attr = re_attr_match.split(command)[1:3]
  97. base = base.strip()
  98. try:
  99. obj = _retrieve_obj(base, context)
  100. except Exception:
  101. return []
  102. attrs = dir(obj)
  103. try:
  104. attrs = generics.complete_object(obj, attrs)
  105. except TryNext:
  106. pass
  107. omit__names = None
  108. try:
  109. # support >=ipython-0.12
  110. omit__names = get_ipython().Completer.omit__names
  111. except AttributeError:
  112. pass
  113. if omit__names is None:
  114. try:
  115. # support ipython-0.11
  116. omit__names = get_ipython().readline_omit__names
  117. except AttributeError:
  118. pass
  119. if omit__names is None:
  120. try:
  121. # support <ipython-0.11
  122. omit__names = get_ipython().options.readline_omit__names
  123. except AttributeError:
  124. omit__names = 0
  125. if omit__names == 1:
  126. attrs = [a for a in attrs if not a.startswith('__')]
  127. elif omit__names == 2:
  128. attrs = [a for a in attrs if not a.startswith('_')]
  129. readline.set_completer_delims(' =')
  130. return ["%s.%s" % (base, a) for a in attrs if a[:len(attr)] == attr]
  131. def h5py_completer(self, event):
  132. """ Completer function to be loaded into IPython """
  133. base = re_object_match.split(event.line)[1]
  134. if not isinstance(self._ofind(base).get('obj'), (AttributeManager, HLObject)):
  135. raise TryNext
  136. try:
  137. return h5py_attr_completer(self, event.line)
  138. except ValueError:
  139. pass
  140. try:
  141. return h5py_item_completer(self, event.line)
  142. except ValueError:
  143. pass
  144. return []
  145. def load_ipython_extension(ip=None):
  146. """ Load completer function into IPython """
  147. if ip is None:
  148. ip = get_ipython()
  149. ip.set_hook('complete_command', h5py_completer, re_key=r"(?:.*\=)?(.+?)\[")