util.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. # Licensed to the Apache Software Foundation (ASF) under one
  2. # or more contributor license agreements. See the NOTICE file
  3. # distributed with this work for additional information
  4. # regarding copyright ownership. The ASF licenses this file
  5. # to you under the Apache License, Version 2.0 (the
  6. # "License"); you may not use this file except in compliance
  7. # with the License. You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing,
  12. # software distributed under the License is distributed on an
  13. # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. # KIND, either express or implied. See the License for the
  15. # specific language governing permissions and limitations
  16. # under the License.
  17. # Miscellaneous utility code
  18. import contextlib
  19. import functools
  20. import gc
  21. import pathlib
  22. import socket
  23. import sys
  24. import types
  25. import warnings
  26. _DEPR_MSG = (
  27. "pyarrow.{} is deprecated as of {}, please use pyarrow.{} instead."
  28. )
  29. def implements(f):
  30. def decorator(g):
  31. g.__doc__ = f.__doc__
  32. return g
  33. return decorator
  34. def _deprecate_api(old_name, new_name, api, next_version):
  35. msg = _DEPR_MSG.format(old_name, next_version, new_name)
  36. def wrapper(*args, **kwargs):
  37. warnings.warn(msg, FutureWarning)
  38. return api(*args, **kwargs)
  39. return wrapper
  40. def _deprecate_class(old_name, new_class, next_version,
  41. instancecheck=True):
  42. """
  43. Raise warning if a deprecated class is used in an isinstance check.
  44. """
  45. class _DeprecatedMeta(type):
  46. def __instancecheck__(self, other):
  47. warnings.warn(
  48. _DEPR_MSG.format(old_name, next_version, new_class.__name__),
  49. FutureWarning,
  50. stacklevel=2
  51. )
  52. return isinstance(other, new_class)
  53. return _DeprecatedMeta(old_name, (new_class,), {})
  54. def _is_iterable(obj):
  55. try:
  56. iter(obj)
  57. return True
  58. except TypeError:
  59. return False
  60. def _is_path_like(path):
  61. # PEP519 filesystem path protocol is available from python 3.6, so pathlib
  62. # doesn't implement __fspath__ for earlier versions
  63. return (isinstance(path, str) or
  64. hasattr(path, '__fspath__') or
  65. isinstance(path, pathlib.Path))
  66. def _stringify_path(path):
  67. """
  68. Convert *path* to a string or unicode path if possible.
  69. """
  70. if isinstance(path, str):
  71. return path
  72. # checking whether path implements the filesystem protocol
  73. try:
  74. return path.__fspath__() # new in python 3.6
  75. except AttributeError:
  76. # fallback pathlib ckeck for earlier python versions than 3.6
  77. if isinstance(path, pathlib.Path):
  78. return str(path)
  79. raise TypeError("not a path-like object")
  80. def product(seq):
  81. """
  82. Return a product of sequence items.
  83. """
  84. return functools.reduce(lambda a, b: a*b, seq, 1)
  85. def get_contiguous_span(shape, strides, itemsize):
  86. """
  87. Return a contiguous span of N-D array data.
  88. Parameters
  89. ----------
  90. shape : tuple
  91. strides : tuple
  92. itemsize : int
  93. Specify array shape data
  94. Returns
  95. -------
  96. start, end : int
  97. The span end points.
  98. """
  99. if not strides:
  100. start = 0
  101. end = itemsize * product(shape)
  102. else:
  103. start = 0
  104. end = itemsize
  105. for i, dim in enumerate(shape):
  106. if dim == 0:
  107. start = end = 0
  108. break
  109. stride = strides[i]
  110. if stride > 0:
  111. end += stride * (dim - 1)
  112. elif stride < 0:
  113. start += stride * (dim - 1)
  114. if end - start != itemsize * product(shape):
  115. raise ValueError('array data is non-contiguous')
  116. return start, end
  117. def find_free_port():
  118. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  119. with contextlib.closing(sock) as sock:
  120. sock.bind(('', 0))
  121. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  122. return sock.getsockname()[1]
  123. def guid():
  124. from uuid import uuid4
  125. return uuid4().hex
  126. def _break_traceback_cycle_from_frame(frame):
  127. # Clear local variables in all inner frames, so as to break the
  128. # reference cycle.
  129. this_frame = sys._getframe(0)
  130. refs = gc.get_referrers(frame)
  131. while refs:
  132. for frame in refs:
  133. if frame is not this_frame and isinstance(frame, types.FrameType):
  134. break
  135. else:
  136. # No frame found in referrers (finished?)
  137. break
  138. refs = None
  139. # Clear the frame locals, to try and break the cycle (it is
  140. # somewhere along the chain of execution frames).
  141. frame.clear()
  142. # To visit the inner frame, we need to find it among the
  143. # referers of this frame (while `frame.f_back` would let
  144. # us visit the outer frame).
  145. refs = gc.get_referrers(frame)
  146. refs = frame = this_frame = None