def _get_namedrange(book, rangename, sheetname=None):
def cond(namedef):<EOL><INDENT>if namedef.type.upper() == "<STR_LIT>":<EOL><INDENT>if namedef.name.upper() == rangename.upper():<EOL><INDENT>if sheetname is None:<EOL><INDENT>if not namedef.localSheetId:<EOL><INDENT>return True<EOL><DEDENT><DEDENT>else:  <EOL><INDENT>sheet_id = [sht.upper() for sht in book.sheetnames].index(<EOL>sheetname.upper()<EOL>)<EOL>if namedef.localSheetId == sheet_id:<EOL><INDENT>return True<EOL><DEDENT><DEDENT><DEDENT><DEDENT>return False<EOL><DEDENT>def get_destinations(name_def):<EOL><INDENT>"""<STR_LIT>"""<EOL>from openpyxl.formula import Tokenizer<EOL>from openpyxl.utils.cell import SHEETRANGE_RE<EOL>if name_def.type == "<STR_LIT>":<EOL><INDENT>tok = Tokenizer("<STR_LIT:=>" + name_def.value)<EOL>for part in tok.items:<EOL><INDENT>if part.subtype == "<STR_LIT>":<EOL><INDENT>m = SHEETRANGE_RE.match(part.value)<EOL>if m.group("<STR_LIT>"):<EOL><INDENT>sheet_name = m.group("<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>sheet_name = m.group("<STR_LIT>")<EOL><DEDENT>yield sheet_name, m.group("<STR_LIT>")<EOL><DEDENT><DEDENT><DEDENT><DEDENT>namedef = next(<EOL>(item for item in book.defined_names.definedName if cond(item)), None<EOL>)<EOL>if namedef is None:<EOL><INDENT>return None<EOL><DEDENT>dests = get_destinations(namedef)<EOL>xlranges = []<EOL>sheetnames_upper = [name.upper() for name in book.sheetnames]<EOL>for sht, addr in dests:<EOL><INDENT>if sheetname:<EOL><INDENT>sht = sheetname<EOL><DEDENT>index = sheetnames_upper.index(sht.upper())<EOL>xlranges.append(book.worksheets[index][addr])<EOL><DEDENT>if len(xlranges) == <NUM_LIT:1>:<EOL><INDENT>return xlranges[<NUM_LIT:0>]<EOL><DEDENT>else:<EOL><INDENT>return xlranges<EOL><DEDENT>
Get range from a workbook.

    A workbook can contain multiple definitions for a single name,
    as a name can be defined for the entire book or for
    a particular sheet.

    If sheet is None, the book-wide def is searched,
    otherwise sheet-local def is looked up.

    Args:
        book: An openpyxl workbook object.
        rangename (str): Range expression, such as "A1", "$G4:$K10",
            named range "NamedRange1".
        sheetname (str, optional): None for book-wide name def,
            sheet name for sheet-local named range.

    Returns:
        Range object specified by the name.