diff --git a/docs/misc.rst b/docs/misc.rst index 0c2f2b1..8f7bb4a 100644 --- a/docs/misc.rst +++ b/docs/misc.rst @@ -89,3 +89,15 @@ Miscellanea >>> foo() >>> foo() >>> + + +.. py:function:: pydu.misc.super_len(obj) + + Get length of object which has attribute named `__len__`, `len`, `fileno`, `tell`, + such as `list`, `tuple`, `dict`, `file` and so on. + + >>> from pydu.misc import super_len + >>> super_len([1, 2]) + 2 + >>> super_len(open('test', 'w')) + 0 diff --git a/pydu/misc.py b/pydu/misc.py index 8a43dee..ccce52b 100644 --- a/pydu/misc.py +++ b/pydu/misc.py @@ -162,27 +162,27 @@ def memoize_when_activated(fun): # https://github.com/requests/requests/blob/master/requests/utils.py -def super_len(o): +def super_len(obj): total_length = None current_position = 0 - if hasattr(o, '__len__'): - total_length = len(o) + if hasattr(obj, '__len__'): + total_length = len(obj) - elif hasattr(o, 'len'): - total_length = o.len + elif hasattr(obj, 'len'): + total_length = obj.len - elif hasattr(o, 'fileno'): + elif hasattr(obj, 'fileno'): try: - fileno = o.fileno() + fileno = obj.fileno() except io.UnsupportedOperation: pass else: total_length = os.fstat(fileno).st_size - if hasattr(o, 'tell'): + if hasattr(obj, 'tell'): try: - current_position = o.tell() + current_position = obj.tell() except (OSError, IOError): # This can happen in some weird situations, such as when the file # is actually a special file descriptor like stdin. In this @@ -191,16 +191,16 @@ def super_len(o): if total_length is not None: current_position = total_length else: - if hasattr(o, 'seek') and total_length is None: + if hasattr(obj, 'seek') and total_length is None: # StringIO and BytesIO have seek but no useable fileno try: # seek to end of file - o.seek(0, 2) - total_length = o.tell() + obj.seek(0, 2) + total_length = obj.tell() # seek back to current position to support # partially read file-like objects - o.seek(current_position or 0) + obj.seek(current_position or 0) except (OSError, IOError): total_length = 0