]>
Commit | Line | Data |
---|---|---|
1d09f67e TL |
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 | ||
18 | # Miscellaneous utility code | |
19 | ||
20 | import contextlib | |
21 | import functools | |
22 | import gc | |
23 | import pathlib | |
24 | import socket | |
25 | import sys | |
26 | import types | |
27 | import warnings | |
28 | ||
29 | ||
30 | _DEPR_MSG = ( | |
31 | "pyarrow.{} is deprecated as of {}, please use pyarrow.{} instead." | |
32 | ) | |
33 | ||
34 | ||
35 | def implements(f): | |
36 | def decorator(g): | |
37 | g.__doc__ = f.__doc__ | |
38 | return g | |
39 | return decorator | |
40 | ||
41 | ||
42 | def _deprecate_api(old_name, new_name, api, next_version): | |
43 | msg = _DEPR_MSG.format(old_name, next_version, new_name) | |
44 | ||
45 | def wrapper(*args, **kwargs): | |
46 | warnings.warn(msg, FutureWarning) | |
47 | return api(*args, **kwargs) | |
48 | return wrapper | |
49 | ||
50 | ||
51 | def _deprecate_class(old_name, new_class, next_version, | |
52 | instancecheck=True): | |
53 | """ | |
54 | Raise warning if a deprecated class is used in an isinstance check. | |
55 | """ | |
56 | class _DeprecatedMeta(type): | |
57 | def __instancecheck__(self, other): | |
58 | warnings.warn( | |
59 | _DEPR_MSG.format(old_name, next_version, new_class.__name__), | |
60 | FutureWarning, | |
61 | stacklevel=2 | |
62 | ) | |
63 | return isinstance(other, new_class) | |
64 | ||
65 | return _DeprecatedMeta(old_name, (new_class,), {}) | |
66 | ||
67 | ||
68 | def _is_iterable(obj): | |
69 | try: | |
70 | iter(obj) | |
71 | return True | |
72 | except TypeError: | |
73 | return False | |
74 | ||
75 | ||
76 | def _is_path_like(path): | |
77 | # PEP519 filesystem path protocol is available from python 3.6, so pathlib | |
78 | # doesn't implement __fspath__ for earlier versions | |
79 | return (isinstance(path, str) or | |
80 | hasattr(path, '__fspath__') or | |
81 | isinstance(path, pathlib.Path)) | |
82 | ||
83 | ||
84 | def _stringify_path(path): | |
85 | """ | |
86 | Convert *path* to a string or unicode path if possible. | |
87 | """ | |
88 | if isinstance(path, str): | |
89 | return path | |
90 | ||
91 | # checking whether path implements the filesystem protocol | |
92 | try: | |
93 | return path.__fspath__() # new in python 3.6 | |
94 | except AttributeError: | |
95 | # fallback pathlib ckeck for earlier python versions than 3.6 | |
96 | if isinstance(path, pathlib.Path): | |
97 | return str(path) | |
98 | ||
99 | raise TypeError("not a path-like object") | |
100 | ||
101 | ||
102 | def product(seq): | |
103 | """ | |
104 | Return a product of sequence items. | |
105 | """ | |
106 | return functools.reduce(lambda a, b: a*b, seq, 1) | |
107 | ||
108 | ||
109 | def get_contiguous_span(shape, strides, itemsize): | |
110 | """ | |
111 | Return a contiguous span of N-D array data. | |
112 | ||
113 | Parameters | |
114 | ---------- | |
115 | shape : tuple | |
116 | strides : tuple | |
117 | itemsize : int | |
118 | Specify array shape data | |
119 | ||
120 | Returns | |
121 | ------- | |
122 | start, end : int | |
123 | The span end points. | |
124 | """ | |
125 | if not strides: | |
126 | start = 0 | |
127 | end = itemsize * product(shape) | |
128 | else: | |
129 | start = 0 | |
130 | end = itemsize | |
131 | for i, dim in enumerate(shape): | |
132 | if dim == 0: | |
133 | start = end = 0 | |
134 | break | |
135 | stride = strides[i] | |
136 | if stride > 0: | |
137 | end += stride * (dim - 1) | |
138 | elif stride < 0: | |
139 | start += stride * (dim - 1) | |
140 | if end - start != itemsize * product(shape): | |
141 | raise ValueError('array data is non-contiguous') | |
142 | return start, end | |
143 | ||
144 | ||
145 | def find_free_port(): | |
146 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
147 | with contextlib.closing(sock) as sock: | |
148 | sock.bind(('', 0)) | |
149 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
150 | return sock.getsockname()[1] | |
151 | ||
152 | ||
153 | def guid(): | |
154 | from uuid import uuid4 | |
155 | return uuid4().hex | |
156 | ||
157 | ||
158 | def _break_traceback_cycle_from_frame(frame): | |
159 | # Clear local variables in all inner frames, so as to break the | |
160 | # reference cycle. | |
161 | this_frame = sys._getframe(0) | |
162 | refs = gc.get_referrers(frame) | |
163 | while refs: | |
164 | for frame in refs: | |
165 | if frame is not this_frame and isinstance(frame, types.FrameType): | |
166 | break | |
167 | else: | |
168 | # No frame found in referrers (finished?) | |
169 | break | |
170 | refs = None | |
171 | # Clear the frame locals, to try and break the cycle (it is | |
172 | # somewhere along the chain of execution frames). | |
173 | frame.clear() | |
174 | # To visit the inner frame, we need to find it among the | |
175 | # referers of this frame (while `frame.f_back` would let | |
176 | # us visit the outer frame). | |
177 | refs = gc.get_referrers(frame) | |
178 | refs = frame = this_frame = None |