PageRenderTime 43ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/oct2py/utils.py

https://bitbucket.org/blink1073/oct2py
Python | 219 lines | 191 code | 5 blank | 23 comment | 3 complexity | 5fd53f3ca3c3d4de92afd0d64dc698d4 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. """
  2. .. module:: utils
  3. :synopsis: Miscellaneous helper constructs
  4. .. moduleauthor:: Steven Silvester <steven.silvester@ieee.org>
  5. """
  6. import os
  7. import inspect
  8. import dis
  9. import tempfile
  10. import atexit
  11. from oct2py.compat import PY2
  12. def _remove_temp_files():
  13. """
  14. Remove the created mat files in the user's temp folder
  15. """
  16. import os
  17. import glob
  18. import tempfile
  19. temp = tempfile.NamedTemporaryFile()
  20. temp.close()
  21. dirname = os.path.dirname(temp.name)
  22. for fname in glob.glob(os.path.join(dirname, 'tmp*.mat')):
  23. try:
  24. os.remove(fname)
  25. except OSError: # pragma: no cover
  26. pass
  27. atexit.register(_remove_temp_files)
  28. def get_nout():
  29. """
  30. Return the number of return values the caller is expecting.
  31. Adapted from the ompc project.
  32. Returns
  33. =======
  34. out : int
  35. Number of arguments expected by caller.
  36. """
  37. frame = inspect.currentframe()
  38. # step into the function that called us
  39. # nout is two frames back
  40. frame = frame.f_back.f_back
  41. bytecode = frame.f_code.co_code
  42. instruction = bytecode[frame.f_lasti + 3]
  43. instruction = ord(instruction) if PY2 else instruction
  44. if instruction == dis.opmap['UNPACK_SEQUENCE']:
  45. howmany = bytecode[frame.f_lasti + 4]
  46. howmany = ord(howmany) if PY2 else howmany
  47. return howmany
  48. elif instruction in [dis.opmap['POP_TOP'], dis.opmap['PRINT_EXPR']]:
  49. return 0
  50. return 1
  51. def create_file():
  52. """
  53. Create a MAT file with a random name in the temp directory
  54. Returns
  55. =======
  56. out : str
  57. Random file name with the desired extension
  58. """
  59. temp_file = tempfile.NamedTemporaryFile(suffix='.mat', delete=False)
  60. temp_file.close()
  61. return os.path.abspath(temp_file.name)
  62. class Oct2PyError(Exception):
  63. """ Called when we can't open Octave or Octave throws an error
  64. """
  65. pass
  66. class Struct(dict):
  67. """
  68. Octave style struct, enhanced.
  69. Supports dictionary and attribute style access. Can be pickled,
  70. and supports code completion in a REPL.
  71. Examples
  72. ========
  73. >>> from oct2py import Struct
  74. >>> a = Struct()
  75. >>> a.b = 'spam' # a["b"] == 'spam'
  76. >>> a.c["d"] = 'eggs' # a.c.d == 'eggs'
  77. >>> print(a)
  78. {'c': {'d': 'eggs'}, 'b': 'spam'}
  79. """
  80. def __getattr__(self, attr):
  81. """Access the dictionary keys for unknown attributes."""
  82. try:
  83. return self[attr]
  84. except KeyError:
  85. msg = "'Struct' object has no attribute %s" % attr
  86. raise AttributeError(msg)
  87. def __getitem__(self, attr):
  88. """
  89. Get a dict value; create a Struct if requesting a Struct member.
  90. Do not create a key if the attribute starts with an underscore.
  91. """
  92. if attr in self.keys() or attr.startswith('_'):
  93. return dict.__getitem__(self, attr)
  94. frame = inspect.currentframe()
  95. # step into the function that called us
  96. if frame.f_back.f_back and self._is_allowed(frame.f_back.f_back):
  97. dict.__setitem__(self, attr, Struct())
  98. elif self._is_allowed(frame.f_back):
  99. dict.__setitem__(self, attr, Struct())
  100. return dict.__getitem__(self, attr)
  101. def _is_allowed(self, frame):
  102. """Check for allowed op code in the calling frame"""
  103. allowed = [dis.opmap['STORE_ATTR'], dis.opmap['LOAD_CONST'],
  104. dis.opmap.get('STOP_CODE', 0)]
  105. bytecode = frame.f_code.co_code
  106. instruction = bytecode[frame.f_lasti + 3]
  107. instruction = ord(instruction) if PY2 else instruction
  108. return instruction in allowed
  109. __setattr__ = dict.__setitem__
  110. __delattr__ = dict.__delitem__
  111. @property
  112. def __dict__(self):
  113. """Allow for code completion in a REPL"""
  114. return self.copy()
  115. def get_log(name=None):
  116. """Return a console logger.
  117. Output may be sent to the logger using the `debug`, `info`, `warning`,
  118. `error` and `critical` methods.
  119. Parameters
  120. ----------
  121. name : str
  122. Name of the log.
  123. References
  124. ----------
  125. .. [1] Logging facility for Python,
  126. http://docs.python.org/library/logging.html
  127. """
  128. import logging
  129. if name is None:
  130. name = 'oct2py'
  131. else:
  132. name = 'oct2py.' + name
  133. log = logging.getLogger(name)
  134. log.setLevel(logging.WARN)
  135. return log
  136. def _setup_log():
  137. """Configure root logger.
  138. """
  139. import logging
  140. import sys
  141. try:
  142. handler = logging.StreamHandler(stream=sys.stdout)
  143. except TypeError: # pragma: no cover
  144. handler = logging.StreamHandler(strm=sys.stdout)
  145. log = get_log()
  146. log.addHandler(handler)
  147. log.setLevel(logging.WARN)
  148. log.propagate = False
  149. _setup_log()
  150. def _test(): # pragma: no cover
  151. """Run the doctests for this module
  152. """
  153. doctest.testmod()
  154. if __name__ == "__main__": # pragma: no cover
  155. # import doctest
  156. #_test()
  157. import pickle
  158. a = Struct()
  159. a['foo'] = 3
  160. a['bar'] = 2
  161. a.baz['bar'] = 1
  162. a.bob.charlie = 1
  163. a['fizz']['buzz'] = 3
  164. a['fizz']['bongo']['bear'] = 4
  165. #a['fizz']['bongo']
  166. a['fizz'].dog = 'fido'
  167. #a['fizz'].yappy
  168. #a.micro
  169. #a.baz.dodo
  170. test = Struct()
  171. test.spam = 'eggs'
  172. test.eggs.spam = 'eggs'
  173. test["foo"]["bar"] = 10
  174. p = pickle.dumps(test)
  175. test2 = pickle.loads(p)