Return sexagesimal string of given angle in degrees or hours.

    Parameters
    ----------
    val : float
        The angle (in degrees or hours) that is to be converted into a
        sexagesimal string.
    s1 : str
        Character to be used between the first and second parts of the
        the sexagesimal representation.
    s2 : str
        Character to be used between the second and third parts of the
        the sexagesimal representation.
    s3 : str
        Character to be used after the third part of the sexagesimal
        representation.
    pre : int
        The final part of the sexagesimal number is rounded to these
        many decimal places. This can be negative.
    trunc : bool
        If True then the third part of the sexagesimal number is
        truncated to `pre` decimal places, instead of rounding.
    lower, upper : float
        If `lower` and `upper` are given then the given value is
        normalized into the this range before converting to sexagesimal
        string.
    b : bool
        This affect how the normalization is performed. See notes. This
        works exactly like that for the function `normalize()`.
    upper_trim : bool
        If `lower` and `upper` are given, then if the first part of the
        sexagesimal number equals `upper`, it is replaced with
        `lower`. For examples, "12 00 00" gets turned into "00 00
        00".

    See also
    --------
    normalize
    deci2sexa

    Examples
    --------
    >>> fmt_angle(12.348978659, pre=4, trunc=True)
    '+12 20 56.3231'
    >>> fmt_angle(12.348978659, pre=5)
    '+12 20 56.32317'
    >>> fmt_angle(12.348978659, s1='HH ', s2='MM ', s3='SS', pre=5)
    '+12HH 20MM 56.32317SS'

    >>> x = 23+59/60.0+59.99999/3600.0
    >>> fmt_angle(x)
    '+24 00 00.000'
    >>> fmt_angle(x, lower=0, upper=24, upper_trim=True)
    '+00 00 00.000'
    >>> fmt_angle(x, pre=5)
    '+23 59 59.99999'
    >>> fmt_angle(-x, lower=0, upper=24, upper_trim=True)
    '+00 00 00.000'
    >>> fmt_angle(-x)
    '-24 00 00.000'

def fmt_angle(val, s1=" ", s2=" ", s3="", pre=3, trunc=False,
              lower=None, upper=None, b=False, upper_trim=False):
    """Return sexagesimal string of given angle in degrees or hours.

    Parameters
    ----------
    val : float
        The angle (in degrees or hours) that is to be converted into a
        sexagesimal string.
    s1 : str
        Character to be used between the first and second parts of the
        the sexagesimal representation.
    s2 : str
        Character to be used between the second and third parts of the
        the sexagesimal representation.
    s3 : str
        Character to be used after the third part of the sexagesimal
        representation.
    pre : int
        The final part of the sexagesimal number is rounded to these
        many decimal places. This can be negative.
    trunc : bool
        If True then the third part of the sexagesimal number is
        truncated to `pre` decimal places, instead of rounding.
    lower, upper : float
        If `lower` and `upper` are given then the given value is
        normalized into the this range before converting to sexagesimal
        string.
    b : bool
        This affect how the normalization is performed. See notes. This
        works exactly like that for the function `normalize()`.
    upper_trim : bool
        If `lower` and `upper` are given, then if the first part of the
        sexagesimal number equals `upper`, it is replaced with
        `lower`. For examples, "12 00 00" gets turned into "00 00
        00".

    See also
    --------
    normalize
    deci2sexa

    Examples
    --------
    >>> fmt_angle(12.348978659, pre=4, trunc=True)
    '+12 20 56.3231'
    >>> fmt_angle(12.348978659, pre=5)
    '+12 20 56.32317'
    >>> fmt_angle(12.348978659, s1='HH ', s2='MM ', s3='SS', pre=5)
    '+12HH 20MM 56.32317SS'

    >>> x = 23+59/60.0+59.99999/3600.0
    >>> fmt_angle(x)
    '+24 00 00.000'
    >>> fmt_angle(x, lower=0, upper=24, upper_trim=True)
    '+00 00 00.000'
    >>> fmt_angle(x, pre=5)
    '+23 59 59.99999'
    >>> fmt_angle(-x, lower=0, upper=24, upper_trim=True)
    '+00 00 00.000'
    >>> fmt_angle(-x)
    '-24 00 00.000'

    """
    x = deci2sexa(val, pre=pre, trunc=trunc, lower=lower, upper=upper,
                  upper_trim=upper_trim, b=b)

    left_digits_plus_deci_point = 3 if pre > 0 else 2
    p = "{3:0" + "{0}.{1}".format(pre + left_digits_plus_deci_point, pre) + "f}" + s3
    p = "{0}{1:02d}" + s1 + "{2:02d}" + s2 + p

    return p.format("-" if x[0] < 0 else "+", *x[1:])