147 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
from requests.exceptions import ConnectionError, RequestException
 | 
						|
 | 
						|
 | 
						|
class Attrs:
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def call(cls, f, **kwargs):
 | 
						|
        return f(cls(**kwargs))
 | 
						|
 | 
						|
    def __init__(self, **kwargs):
 | 
						|
        self.attrs = kwargs
 | 
						|
 | 
						|
    def __getattr__(self, attr):
 | 
						|
        return self.attrs.get(attr)
 | 
						|
 | 
						|
 | 
						|
def get_short_error_message(e: Exception):
 | 
						|
    '''Generate a reasonable short message why the HTTP request failed'''
 | 
						|
 | 
						|
    if isinstance(e, RequestException) and e.response is not None:
 | 
						|
        # e.g. "401 Unauthorized"
 | 
						|
        return '{} {}'.format(e.response.status_code, e.response.reason)
 | 
						|
    elif isinstance(e, ConnectionError):
 | 
						|
        # e.g. "ConnectionError" or "ConnectTimeout"
 | 
						|
        return e.__class__.__name__
 | 
						|
    else:
 | 
						|
        return str(e)
 | 
						|
 | 
						|
 | 
						|
def identity(value, *_, **__):
 | 
						|
    """
 | 
						|
    Trivial identity function: return the value passed in its first argument.
 | 
						|
 | 
						|
    Examples:
 | 
						|
 | 
						|
    >>> identity(42)
 | 
						|
    42
 | 
						|
 | 
						|
    >>> list(
 | 
						|
    ...     filter(
 | 
						|
    ...         identity,
 | 
						|
    ...         [None, False, True, 0, 1, list(), set(), dict()],
 | 
						|
    ...     ),
 | 
						|
    ... )
 | 
						|
    [True, 1]
 | 
						|
    """
 | 
						|
 | 
						|
    return value
 | 
						|
 | 
						|
 | 
						|
def const(value, *_, **__):
 | 
						|
    """
 | 
						|
    Given a value, returns a function that simply returns that value.
 | 
						|
 | 
						|
    Example:
 | 
						|
    >>> f = const(42)
 | 
						|
    >>> f()
 | 
						|
    42
 | 
						|
    >>> f()
 | 
						|
    42
 | 
						|
    """
 | 
						|
 | 
						|
    return lambda *_, **__: value
 | 
						|
 | 
						|
 | 
						|
def catching(computation, catcher=identity, exception=Exception):
 | 
						|
    """
 | 
						|
    Catch exceptions.
 | 
						|
 | 
						|
    Call the provided computation with no arguments.  If it throws an exception
 | 
						|
    of the provided exception class (or any exception, if no class is provided),
 | 
						|
    return the result of calling the catcher function with the exception as the
 | 
						|
    sole argument.  If no catcher function is specified, return the exception.
 | 
						|
 | 
						|
    Examples:
 | 
						|
 | 
						|
    Catch a KeyError and return the exception itself:
 | 
						|
    >>> catching(lambda: {'foo': 'bar'}['meh'])
 | 
						|
    KeyError('meh',)
 | 
						|
 | 
						|
    Catch a KeyError and return a default value:
 | 
						|
    >>> catching(
 | 
						|
    ...     computation=lambda: {'foo': 'bar'}['meh'],
 | 
						|
    ...     catcher=const('nope'),
 | 
						|
    ... )
 | 
						|
    'nope'
 | 
						|
    """
 | 
						|
 | 
						|
    try:
 | 
						|
        return computation()
 | 
						|
    except exception as e:
 | 
						|
        return catcher(e)
 | 
						|
 | 
						|
 | 
						|
def defaulting(computation, default=None, exception=Exception):
 | 
						|
    """
 | 
						|
    Like `catching`, but just return a default value if an exception is caught.
 | 
						|
 | 
						|
    If no default value is supplied, default to None.
 | 
						|
 | 
						|
    Examples:
 | 
						|
 | 
						|
    Catch a KeyError and return a default value, like the `get` method:
 | 
						|
    >>> defaulting(lambda: {'foo': 'bar'}['meh'], 'nope')
 | 
						|
    'nope'
 | 
						|
 | 
						|
    Turn a ZeroDivisionError into None:
 | 
						|
    >>> defaulting(lambda: 1/0) == None
 | 
						|
    True
 | 
						|
    """
 | 
						|
 | 
						|
    return catching(
 | 
						|
        computation=computation,
 | 
						|
        catcher=const(default),
 | 
						|
        exception=exception,
 | 
						|
    )
 | 
						|
 | 
						|
 | 
						|
def these(what, where=None):
 | 
						|
    """
 | 
						|
    Combinator for yielding multiple values with property access.
 | 
						|
 | 
						|
    Yields from the values generated by an attribute of the given object, or
 | 
						|
    the values generated by the given object itself if no attribute key is
 | 
						|
    specified.
 | 
						|
 | 
						|
    Examples:
 | 
						|
 | 
						|
    No attribute key specified; yields from the given object:
 | 
						|
    >>> these(['foo', 'bar'])
 | 
						|
    ['foo', 'bar']
 | 
						|
 | 
						|
    An attribute key is specified; yields from the values generated by the
 | 
						|
    specified attribute's value:
 | 
						|
    object:
 | 
						|
    >>> these({'foo': ['bar', 'baz']}, 'foo')
 | 
						|
    ['bar', 'baz']
 | 
						|
 | 
						|
    An invalid attribute key is specified; yields nothing:
 | 
						|
    >>> these({'foo': ['bar', 'baz']}, 'meh')
 | 
						|
    []
 | 
						|
    """
 | 
						|
 | 
						|
    if not where:
 | 
						|
        return what
 | 
						|
    return what[where] if where in what else []
 |