1""" basic inference routines """
2
3from __future__ import annotations
4
5from collections import abc
6from numbers import Number
7import re
8from typing import Pattern
9
10import numpy as np
11
12from pandas._libs import lib
13
14is_bool = lib.is_bool
15
16is_integer = lib.is_integer
17
18is_float = lib.is_float
19
20is_complex = lib.is_complex
21
22is_scalar = lib.is_scalar
23
24is_decimal = lib.is_decimal
25
26is_interval = lib.is_interval
27
28is_list_like = lib.is_list_like
29
30is_iterator = lib.is_iterator
31
32
33def is_number(obj) -> bool:
34 """
35 Check if the object is a number.
36
37 Returns True when the object is a number, and False if is not.
38
39 Parameters
40 ----------
41 obj : any type
42 The object to check if is a number.
43
44 Returns
45 -------
46 bool
47 Whether `obj` is a number or not.
48
49 See Also
50 --------
51 api.types.is_integer: Checks a subgroup of numbers.
52
53 Examples
54 --------
55 >>> from pandas.api.types import is_number
56 >>> is_number(1)
57 True
58 >>> is_number(7.15)
59 True
60
61 Booleans are valid because they are int subclass.
62
63 >>> is_number(False)
64 True
65
66 >>> is_number("foo")
67 False
68 >>> is_number("5")
69 False
70 """
71 return isinstance(obj, (Number, np.number))
72
73
74def iterable_not_string(obj) -> bool:
75 """
76 Check if the object is an iterable but not a string.
77
78 Parameters
79 ----------
80 obj : The object to check.
81
82 Returns
83 -------
84 is_iter_not_string : bool
85 Whether `obj` is a non-string iterable.
86
87 Examples
88 --------
89 >>> iterable_not_string([1, 2, 3])
90 True
91 >>> iterable_not_string("foo")
92 False
93 >>> iterable_not_string(1)
94 False
95 """
96 return isinstance(obj, abc.Iterable) and not isinstance(obj, str)
97
98
99def is_file_like(obj) -> bool:
100 """
101 Check if the object is a file-like object.
102
103 For objects to be considered file-like, they must
104 be an iterator AND have either a `read` and/or `write`
105 method as an attribute.
106
107 Note: file-like objects must be iterable, but
108 iterable objects need not be file-like.
109
110 Parameters
111 ----------
112 obj : The object to check
113
114 Returns
115 -------
116 bool
117 Whether `obj` has file-like properties.
118
119 Examples
120 --------
121 >>> import io
122 >>> from pandas.api.types import is_file_like
123 >>> buffer = io.StringIO("data")
124 >>> is_file_like(buffer)
125 True
126 >>> is_file_like([1, 2, 3])
127 False
128 """
129 if not (hasattr(obj, "read") or hasattr(obj, "write")):
130 return False
131
132 return bool(hasattr(obj, "__iter__"))
133
134
135def is_re(obj) -> bool:
136 """
137 Check if the object is a regex pattern instance.
138
139 Parameters
140 ----------
141 obj : The object to check
142
143 Returns
144 -------
145 bool
146 Whether `obj` is a regex pattern.
147
148 Examples
149 --------
150 >>> from pandas.api.types import is_re
151 >>> import re
152 >>> is_re(re.compile(".*"))
153 True
154 >>> is_re("foo")
155 False
156 """
157 return isinstance(obj, Pattern)
158
159
160def is_re_compilable(obj) -> bool:
161 """
162 Check if the object can be compiled into a regex pattern instance.
163
164 Parameters
165 ----------
166 obj : The object to check
167
168 Returns
169 -------
170 bool
171 Whether `obj` can be compiled as a regex pattern.
172
173 Examples
174 --------
175 >>> from pandas.api.types import is_re_compilable
176 >>> is_re_compilable(".*")
177 True
178 >>> is_re_compilable(1)
179 False
180 """
181 try:
182 re.compile(obj)
183 except TypeError:
184 return False
185 else:
186 return True
187
188
189def is_array_like(obj) -> bool:
190 """
191 Check if the object is array-like.
192
193 For an object to be considered array-like, it must be list-like and
194 have a `dtype` attribute.
195
196 Parameters
197 ----------
198 obj : The object to check
199
200 Returns
201 -------
202 is_array_like : bool
203 Whether `obj` has array-like properties.
204
205 Examples
206 --------
207 >>> is_array_like(np.array([1, 2, 3]))
208 True
209 >>> is_array_like(pd.Series(["a", "b"]))
210 True
211 >>> is_array_like(pd.Index(["2016-01-01"]))
212 True
213 >>> is_array_like([1, 2, 3])
214 False
215 >>> is_array_like(("a", "b"))
216 False
217 """
218 return is_list_like(obj) and hasattr(obj, "dtype")
219
220
221def is_nested_list_like(obj) -> bool:
222 """
223 Check if the object is list-like, and that all of its elements
224 are also list-like.
225
226 Parameters
227 ----------
228 obj : The object to check
229
230 Returns
231 -------
232 is_list_like : bool
233 Whether `obj` has list-like properties.
234
235 Examples
236 --------
237 >>> is_nested_list_like([[1, 2, 3]])
238 True
239 >>> is_nested_list_like([{1, 2, 3}, {1, 2, 3}])
240 True
241 >>> is_nested_list_like(["foo"])
242 False
243 >>> is_nested_list_like([])
244 False
245 >>> is_nested_list_like([[1, 2, 3], 1])
246 False
247
248 Notes
249 -----
250 This won't reliably detect whether a consumable iterator (e. g.
251 a generator) is a nested-list-like without consuming the iterator.
252 To avoid consuming it, we always return False if the outer container
253 doesn't define `__len__`.
254
255 See Also
256 --------
257 is_list_like
258 """
259 return (
260 is_list_like(obj)
261 and hasattr(obj, "__len__")
262 and len(obj) > 0
263 and all(is_list_like(item) for item in obj)
264 )
265
266
267def is_dict_like(obj) -> bool:
268 """
269 Check if the object is dict-like.
270
271 Parameters
272 ----------
273 obj : The object to check
274
275 Returns
276 -------
277 bool
278 Whether `obj` has dict-like properties.
279
280 Examples
281 --------
282 >>> from pandas.api.types import is_dict_like
283 >>> is_dict_like({1: 2})
284 True
285 >>> is_dict_like([1, 2, 3])
286 False
287 >>> is_dict_like(dict)
288 False
289 >>> is_dict_like(dict())
290 True
291 """
292 dict_like_attrs = ("__getitem__", "keys", "__contains__")
293 return (
294 all(hasattr(obj, attr) for attr in dict_like_attrs)
295 # [GH 25196] exclude classes
296 and not isinstance(obj, type)
297 )
298
299
300def is_named_tuple(obj) -> bool:
301 """
302 Check if the object is a named tuple.
303
304 Parameters
305 ----------
306 obj : The object to check
307
308 Returns
309 -------
310 bool
311 Whether `obj` is a named tuple.
312
313 Examples
314 --------
315 >>> from collections import namedtuple
316 >>> from pandas.api.types import is_named_tuple
317 >>> Point = namedtuple("Point", ["x", "y"])
318 >>> p = Point(1, 2)
319 >>>
320 >>> is_named_tuple(p)
321 True
322 >>> is_named_tuple((1, 2))
323 False
324 """
325 return isinstance(obj, abc.Sequence) and hasattr(obj, "_fields")
326
327
328def is_hashable(obj) -> bool:
329 """
330 Return True if hash(obj) will succeed, False otherwise.
331
332 Some types will pass a test against collections.abc.Hashable but fail when
333 they are actually hashed with hash().
334
335 Distinguish between these and other types by trying the call to hash() and
336 seeing if they raise TypeError.
337
338 Returns
339 -------
340 bool
341
342 Examples
343 --------
344 >>> import collections
345 >>> from pandas.api.types import is_hashable
346 >>> a = ([],)
347 >>> isinstance(a, collections.abc.Hashable)
348 True
349 >>> is_hashable(a)
350 False
351 """
352 # Unfortunately, we can't use isinstance(obj, collections.abc.Hashable),
353 # which can be faster than calling hash. That is because numpy scalars
354 # fail this test.
355
356 # Reconsider this decision once this numpy bug is fixed:
357 # https://github.com/numpy/numpy/issues/5562
358
359 try:
360 hash(obj)
361 except TypeError:
362 return False
363 else:
364 return True
365
366
367def is_sequence(obj) -> bool:
368 """
369 Check if the object is a sequence of objects.
370 String types are not included as sequences here.
371
372 Parameters
373 ----------
374 obj : The object to check
375
376 Returns
377 -------
378 is_sequence : bool
379 Whether `obj` is a sequence of objects.
380
381 Examples
382 --------
383 >>> l = [1, 2, 3]
384 >>>
385 >>> is_sequence(l)
386 True
387 >>> is_sequence(iter(l))
388 False
389 """
390 try:
391 iter(obj) # Can iterate over it.
392 len(obj) # Has a length associated with it.
393 return not isinstance(obj, (str, bytes))
394 except (TypeError, AttributeError):
395 return False
396
397
398def is_dataclass(item):
399 """
400 Checks if the object is a data-class instance
401
402 Parameters
403 ----------
404 item : object
405
406 Returns
407 --------
408 is_dataclass : bool
409 True if the item is an instance of a data-class,
410 will return false if you pass the data class itself
411
412 Examples
413 --------
414 >>> from dataclasses import dataclass
415 >>> @dataclass
416 ... class Point:
417 ... x: int
418 ... y: int
419
420 >>> is_dataclass(Point)
421 False
422 >>> is_dataclass(Point(0,2))
423 True
424
425 """
426 try:
427 import dataclasses
428
429 return dataclasses.is_dataclass(item) and not isinstance(item, type)
430 except ImportError:
431 return False