The lab provides practice using the Python documentation (specifically, the documentation on built-in functions), and on handling and raising exceptions.
May 3, 2022.
Instructions:
Modify this notebook by adding the Python code described below.
Test your code using the menu item Cell ► Run All
Save the notebook (the .ipynb file) and upload it to the appropriate Assignment folder on the course web site.
The documentation in the Built-in Functions section of the Python Standard Library documentation describes Python's built-in functions.
Define a 4-element tuple named builtins that contains the following
Python functions.  The entries in the tuple should be 
the functions, not the names of the functions.
a function that returns True if any of the values of the iterable argument
are true.  This is the function f() for which, for example,
f([0,False,'']) returns False while f([1,False,'']) returns True.
the function that is the constructor for the complex type
the function that adds the items of an iterable and returns the total
the function that converts an integer number to a binary string prefixed with 0b
For example, your answer might look like:
builtins = (hash,help,hex,id)
builtins = (any,complex,sum,bin)
Write a function checkgood(f,l) that calls the function f() with successive values from the list l
and returns a list with the values for which calling f() does not cause a ValueError exception.
Include items for which no exception or another exception is raised by f()
For example, if the function startslowercase() were defined as:
    def startslowercase(x):
        if type(x) != str or len(x) <= 0 or x[0] != 'a':
            raise ValueError
        else:
            raise UserWarning
Then checkgood(startslowercase,['a', 'ABC', 1, '', 'abc']) should return ['a', 'abc']
You do not need to define f() except for testing.  The marking code will pass your checkgood() function a different function f().
def startslowercase(x):
        if type(x) != str or len(x) <= 0 or x[0] != 'a':
            raise ValueError
        else:
            raise UserWarning
    
def checkgood(f,l):
    r=[]
    for x in l:
        try:
            f(x)
            r.append(x)
        except ValueError:
            pass
        except:
            r.append(x)
    return r
print(checkgood(startslowercase,['a', 'ABC', 1, '', 'abc']))
['a', 'abc']
Write a function doublemark(s) that returns the string ss if s is a single capital letter (A through Z) or raises the
ValueError exception otherwise.
For example if doublemark('a') or doublemark('AA') would raise exception ValueError while doublemark('B') would return "BB".
def doublemark(s):
    if len(s) == 1 and s >= 'A' and s <= 'Z':
        return 2*s
    else:
        raise ValueError
        
for s in ('a','AA','B'):
    try:
        print(doublemark(s))
    except ValueError:
        pass
BB
Write a function numbered(*args) that takes any number of string arguments and returns a single string consisting of the index of each element in *args followed by its value.
For example, numbered('a', 'BB', 'xyz') would return '0a1BB2xyz'.
def numbered(*args):
    s=''
    for i in range(len(args)):
        s+=str(i)
        s+=args[i]
    return s
# or
def numbered(*args):
    # return ''.join([str(i)+s for i,s in enumerate(args)])
    return ''.join([f"{i}{s}" for i,s in enumerate(args)])
numbered('a', 'BB', 'xyz')
'0a1BB2xyz'
# lab validation code; do not modify
def labcheck():
    import random, copy, re, string
    
    def randwords(n,chars=string.ascii_lowercase,nl=(2,5)):
        l = set()
        while len(l)<n:
            l |= set((''.join([chars[random.randint(0,len(chars)-1)] for i in range(random.randint(*nl))]),))
        return list(l)
    
    def q1():
        hashvalues= (
            'c5fe0200d1c7a5139bd18fd22268c4ca8bf45e90',
            '6ff16b36dc77810e63bda254427a1d6965fa127a',
            'e9dff3557ded7414ae530834de7011f1388d202a',
            '9a5d56716d566997fa290054d161af96305aff9a')
        import hashlib
        names=[]
        for f in builtins:
            try:
                names.append(f.__name__)
            except:
                names.append("???")
        for i,s in enumerate(names):
            h = hashlib.sha1()
            h.update(bytes(s,'utf-8'))
            # print(s,h.hexdigest())
            assert h.hexdigest() == hashvalues[i], \
                f"builtins[{i}] ({s}) is not right"
        
    def q2():
        import random
        n = random.randrange(5,8)
        v = list({random.randrange(0,99) for i in range(n)})
        e = [random.randrange(0,3) for i in range(n)]
        ex = [v for i,v in enumerate(v) if e[i] == 0]
        nx = [v for i,v in enumerate(v) if e[i] == 1]
        ox = [v for i,v in enumerate(v) if e[i] == 2]
        # print(n,v,e,ex,nx,ox)
        def f(i):
            if i in ex:
                raise ValueError
            elif i in ox:
                raise RuntimeWarning
            else:
                pass
        ov = copy.deepcopy(v)
        try:
            rl = checkgood(f,v)
        except:
            assert False, f"checkgood() failed to handle an exception."
        assert set(rl) == set(nx)|set(ox), \
            f"checkgood({ov}) returns {rl} but f() raises ValueError exceptions for {ex}"\
            f" and RuntimeWarning exceptions for {ox}"
    
    def q3():
        import random
        n = random.randrange(4,10)
        c = [random.randrange(ord('a'),ord('z')) for i in range(n)]
        u = [random.randrange(0,2) for i in range(n)]
        d = [random.randrange(1,3) for i in range(n)]
        e = [bool(not u[i] or d[i] != 1) for i in range(n)]
        t=[(d*chr(c-32*u),e) for c,u,d,e in zip(c,u,d,e)]
        #print(t)
        for s,e in t:
            try:
                rs = doublemark(s)
                r = False
            except ValueError:
                rs = ''
                r = True
            # print(s,e,r,rs)
            assert e == r and ( e or rs == s+s), \
                f"doublemark('{s}') returned '{rs}' and did {'not ' if not r else ''}raise Exception"
       
    def q4():
        import random
        n=random.randrange(4,7)
        l=randwords(n)
        import copy
        ol = copy.deepcopy(l)
        rl = numbered(*l)
        x=re.split(r'(\d|[A-Za-z]+)',rl)[1::2]
        assert x[::2] == [str(i) for i in range(0,len(ol))] and x[1::2] == ol, \
            f"numbered({','.join([str(i) for i in ol])}) returns {rl}"
    
    for s,i in [(s,s[1:]) for s in locals().keys() if re.search(r'q\d+',s)]:
        try:
            locals()[s]()
            print(f"Question {i} OK.")
        except Exception as e:
            print(f"Failed check for Question {i}: {e}")
            
labcheck()
Question 1 OK. Question 2 OK. Question 3 OK. Question 4 OK.