Check if provided email has a university domain

    - either in .edu domain
        (except public sercices like england.edu or australia.edu)
    - or in .edu.TLD (non-US based institutions, like edu.au)
    - or listed in a public list of universities
        since universities often have department addresses as well, only the end
        is matched. E.g. cs.cmu.edu will match cmu.edu

    :param addr: email address
    :return: bool
    >>> is_university("john@cmu.edu")
    True
    >>> is_university("john@gmail.com")
    False

def is_university(addr):
    # type: (Union[str, unicode]) -> bool
    """ Check if provided email has a university domain

    - either in .edu domain
        (except public sercices like england.edu or australia.edu)
    - or in .edu.TLD (non-US based institutions, like edu.au)
    - or listed in a public list of universities
        since universities often have department addresses as well, only the end
        is matched. E.g. cs.cmu.edu will match cmu.edu

    :param addr: email address
    :return: bool
    >>> is_university("john@cmu.edu")
    True
    >>> is_university("john@gmail.com")
    False
    """
    addr_domain = domain(addr)
    if not addr_domain:  # invalid email
        return False
    chunks = addr_domain.split(".")
    if len(chunks) < 2:  # local or invalid address
        return False

    domains = university_domains()
    # many universitites have departmental emails, such as cs.cmu.edu. However,
    # the original dataset only has top level domain (cmu.edu). So, what we need
    # to do is to strip leading subdomains until match or nothing to strip:
    # isri.cs.cmu.edu (no match) -> cs.cmu.edu (no match) -> cmu.edu (match)
    return (chunks[-1] == "edu" and chunks[-2] not in ("england", "australia"))\
        or chunks[-2] == "edu" \
        or any(".".join(chunks[i:]) in domains for i in range(len(chunks)-1))